diff --git a/Changelog.md b/Changelog.md index 3c6fd316..00b62604 100644 --- a/Changelog.md +++ b/Changelog.md @@ -8,6 +8,7 @@ OpenCore Changelog - Updated docs to cover separating SMBIOS via `UpdateSMBIOSMode` - Fixed rendering macOS installer icons in OpenCanopy - Added APFS support with Fusion Drive and enhanced security +- Added AppleEvent mouse support in OpenCanopy #### v0.5.7 - Added TimeMachine detection to picker diff --git a/Platform/OpenCanopy/GuiApp.c b/Platform/OpenCanopy/GuiApp.c index 895a539c..1bef85cd 100644 --- a/Platform/OpenCanopy/GuiApp.c +++ b/Platform/OpenCanopy/GuiApp.c @@ -434,14 +434,3 @@ InternalGetCursorImage ( GuiContext = (CONST BOOT_PICKER_GUI_CONTEXT *)Context; return &GuiContext->Icons[ICON_CURSOR][ICON_TYPE_BASE]; } - -EFI_STATUS -EFIAPI -UefiUnload ( - IN EFI_HANDLE ImageHandle, - IN EFI_SYSTEM_TABLE *SystemTable - ) -{ - GuiLibDestruct (); - return EFI_SUCCESS; -} diff --git a/Platform/OpenCanopy/GuiApp.h b/Platform/OpenCanopy/GuiApp.h index aa4bb13d..cc3e49ea 100644 --- a/Platform/OpenCanopy/GuiApp.h +++ b/Platform/OpenCanopy/GuiApp.h @@ -79,7 +79,10 @@ typedef struct { BOOLEAN HideAuxiliary; BOOLEAN Refresh; BOOLEAN Light; + BOOLEAN DoneIntroAnimation; UINT8 Scale; + UINT32 CursorDefaultX; + UINT32 CursorDefaultY; } BOOT_PICKER_GUI_CONTEXT; RETURN_STATUS @@ -98,8 +101,9 @@ BootPickerEntriesAdd ( ); VOID -BootPickerEntriesEmpty ( - VOID +BootPickerViewDeinitialize ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext, + IN OUT BOOT_PICKER_GUI_CONTEXT *GuiContext ); CONST GUI_IMAGE * diff --git a/Platform/OpenCanopy/Input/InputSimAbsPtr.c b/Platform/OpenCanopy/Input/InputSimAbsPtr.c index 756557eb..36548f39 100644 --- a/Platform/OpenCanopy/Input/InputSimAbsPtr.c +++ b/Platform/OpenCanopy/Input/InputSimAbsPtr.c @@ -7,10 +7,12 @@ #include +#include #include #include #include +#include #include #include #include @@ -19,8 +21,10 @@ #include "../GuiIo.h" struct GUI_POINTER_CONTEXT_ { + APPLE_EVENT_PROTOCOL *AppleEvent; EFI_SIMPLE_POINTER_PROTOCOL *Pointer; EFI_ABSOLUTE_POINTER_PROTOCOL *AbsPointer; + APPLE_EVENT_HANDLE AppleEventHandle; UINT32 Width; UINT32 Height; UINT32 MaxX; @@ -28,6 +32,8 @@ struct GUI_POINTER_CONTEXT_ { UINT32 X; UINT32 Y; UINT8 LockedBy; + BOOLEAN PrimaryDown; + BOOLEAN SecondaryDown; }; enum { @@ -36,6 +42,71 @@ enum { PointerLockedAbsolute }; +STATIC +VOID +EFIAPI +InternalAppleEventNotification ( + IN APPLE_EVENT_INFORMATION *Information, + IN VOID *NotifyContext + ) +{ + APPLE_POINTER_EVENT_TYPE EventType; + GUI_POINTER_CONTEXT *Context; + + Context = NotifyContext; + + // + // Should not happen but just in case. + // + if ((Information->EventType & APPLE_ALL_MOUSE_EVENTS) == 0) { + return; + } + + EventType = Information->EventData.PointerEventType; + + if ((EventType & APPLE_EVENT_TYPE_MOUSE_MOVED) != 0) { + Context->X = MIN ( + (UINT32) Information->PointerPosition.Horizontal, + Context->MaxX + ); + Context->Y = MIN ( + (UINT32) Information->PointerPosition.Vertical, + Context->MaxY + ); + } + + if ((EventType & APPLE_EVENT_TYPE_MOUSE_DOWN) != 0) { + if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) { + Context->PrimaryDown = TRUE; + } else if ((Information->EventType & APPLE_EVENT_TYPE_RIGHT_BUTTON) != 0) { + Context->SecondaryDown = TRUE; + } + } else if ((EventType & APPLE_EVENT_TYPE_MOUSE_UP) != 0) { + if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) { + Context->PrimaryDown = FALSE; + } else if ((EventType & APPLE_EVENT_TYPE_RIGHT_BUTTON) != 0) { + Context->SecondaryDown = FALSE; + } + } +} + +STATIC +EFI_STATUS +InternalUpdateStateSimpleAppleEvent ( + IN OUT GUI_POINTER_CONTEXT *Context, + OUT GUI_POINTER_STATE *State + ) +{ + ASSERT (Context->AppleEvent != NULL); + + State->X = Context->X; + State->Y = Context->Y; + State->PrimaryDown = Context->PrimaryDown; + State->SecondaryDown = Context->SecondaryDown; + + return EFI_SUCCESS; +} + STATIC UINT32 InternalClipPointerSimple ( @@ -87,7 +158,7 @@ InternalGetInterpolatedValue ( STATIC EFI_STATUS -InternalUpdateStateSimple ( +InternalUpdateStateSimplePointer ( IN OUT GUI_POINTER_CONTEXT *Context, OUT GUI_POINTER_STATE *State ) @@ -97,12 +168,7 @@ InternalUpdateStateSimple ( INT64 InterpolatedX; INT64 InterpolatedY; - ASSERT (Context != NULL); - ASSERT (State != NULL); - - if (Context->Pointer == NULL) { - return EFI_UNSUPPORTED; - } + ASSERT (Context->Pointer != NULL); Status = Context->Pointer->GetState (Context->Pointer, &PointerState); if (EFI_ERROR (Status)) { @@ -156,6 +222,33 @@ InternalUpdateStateSimple ( return EFI_SUCCESS; } +STATIC +EFI_STATUS +InternalUpdateStateSimple ( + IN OUT GUI_POINTER_CONTEXT *Context, + OUT GUI_POINTER_STATE *State + ) +{ + ASSERT (Context != NULL); + ASSERT (State != NULL); + + if (Context->AppleEvent != NULL) { + return InternalUpdateStateSimpleAppleEvent ( + Context, + State + ); + } + + if (Context->Pointer != NULL) { + return InternalUpdateStateSimplePointer ( + Context, + State + ); + } + + return EFI_UNSUPPORTED; +} + STATIC EFI_STATUS InternalUpdateStateAbsolute ( @@ -332,34 +425,75 @@ GuiPointerConstruct ( EFI_STATUS Status; EFI_STATUS Status2; + EFI_TPL OldTpl; + DIMENSION Dimension; ASSERT (DefaultX < Width); ASSERT (DefaultY < Height); + Context.Width = Width; + Context.Height = Height; + Context.MaxX = Width - 1; + Context.MaxY = Height - 1; + Context.X = DefaultX; + Context.Y = DefaultY; + Status = InternalHandleProtocolFallback ( - gST->ConsoleInHandle, - &gEfiSimplePointerProtocolGuid, - (VOID **)&Context.Pointer - ); + gST->ConsoleInHandle, + &gAppleEventProtocolGuid, + (VOID **)&Context.AppleEvent + ); + if (!EFI_ERROR (Status)) { + if (Context.AppleEvent->Revision >= APPLE_EVENT_PROTOCOL_REVISION) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + + Status = Context.AppleEvent->RegisterHandler ( + APPLE_ALL_MOUSE_EVENTS, + InternalAppleEventNotification, + &Context.AppleEventHandle, + &Context + ); + + Dimension.Horizontal = (INT32) DefaultX; + Dimension.Vertical = (INT32) DefaultY; + Context.AppleEvent->SetCursorPosition ( + &Dimension + ); + + gBS->RestoreTPL (OldTpl); + } else { + Status = EFI_UNSUPPORTED; + } + + if (EFI_ERROR (Status)) { + DEBUG (( + DEBUG_WARN, + "OCUI: AppleEvent %u is unsupported - %r\n", + Context.AppleEvent->Revision, + Status + )); + Context.AppleEvent = NULL; + } + } + + if (EFI_ERROR (Status)) { + Status = InternalHandleProtocolFallback ( + gST->ConsoleInHandle, + &gEfiSimplePointerProtocolGuid, + (VOID **)&Context.Pointer + ); + } + Status2 = InternalHandleProtocolFallback ( - gST->ConsoleInHandle, - &gEfiAbsolutePointerProtocolGuid, - (VOID **)&Context.AbsPointer - ); + gST->ConsoleInHandle, + &gEfiAbsolutePointerProtocolGuid, + (VOID **)&Context.AbsPointer + ); + if (EFI_ERROR (Status) && EFI_ERROR (Status2)) { return NULL; } - if (Context.Pointer != NULL) { - Context.X = DefaultX; - Context.Y = DefaultY; - Context.MaxX = Width - 1; - Context.MaxY = Height - 1; - } - - Context.Width = Width; - Context.Height = Height; - return &Context; } @@ -369,4 +503,12 @@ GuiPointerDestruct ( ) { ASSERT (Context != NULL); + + if (Context->AppleEvent != NULL) { + Context->AppleEvent->UnregisterHandler ( + Context->AppleEventHandle + ); + } + + ZeroMem (Context, sizeof (*Context)); } diff --git a/Platform/OpenCanopy/OcBootstrap.c b/Platform/OpenCanopy/OcBootstrap.c index baf5fba8..b7698627 100644 --- a/Platform/OpenCanopy/OcBootstrap.c +++ b/Platform/OpenCanopy/OcBootstrap.c @@ -51,7 +51,23 @@ OcShowMenuByOc ( mGuiContext.HideAuxiliary = Context->HideAuxiliary; mGuiContext.Refresh = FALSE; - BootPickerEntriesEmpty (); + Status = GuiLibConstruct ( + mGuiContext.CursorDefaultX, + mGuiContext.CursorDefaultY + ); + if (RETURN_ERROR (Status)) { + return Status; + } + + Status = BootPickerViewInitialize ( + &mDrawContext, + &mGuiContext, + InternalGetCursorImage + ); + if (RETURN_ERROR (Status)) { + GuiLibDestruct (); + return Status; + } for (Index = 0; Index < Count; ++Index) { Status = BootPickerEntriesAdd ( @@ -61,6 +77,7 @@ OcShowMenuByOc ( Index == DefaultEntry ); if (RETURN_ERROR (Status)) { + GuiLibDestruct (); return Status; } } @@ -68,6 +85,13 @@ OcShowMenuByOc ( GuiDrawLoop (&mDrawContext); ASSERT (mGuiContext.BootEntry != NULL || mGuiContext.Refresh); + // + // Note, it is important to destruct GUI here, as we must ensure + // that keyboard/mouse polling does not conflict with FV2 ui. + // + BootPickerViewDeinitialize (&mDrawContext, &mGuiContext); + GuiLibDestruct (); + *ChosenBootEntry = mGuiContext.BootEntry; Context->HideAuxiliary = mGuiContext.HideAuxiliary; if (mGuiContext.Refresh) { @@ -102,22 +126,11 @@ GuiOcInterfaceRun ( { EFI_STATUS Status; - Status = GuiLibConstruct (0, 0); - if (RETURN_ERROR (Status)) { - return Status; - } - Status = InternalContextConstruct (&mGuiContext, Storage, Context); if (RETURN_ERROR (Status)) { return Status; } - Status = BootPickerViewInitialize ( - &mDrawContext, - &mGuiContext, - InternalGetCursorImage - ); - Context->ShowMenu = OcShowMenuByOc; return OcRunBootPicker (Context); diff --git a/Platform/OpenCanopy/OpenCanopy.c b/Platform/OpenCanopy/OpenCanopy.c index bb793abd..e40365b9 100644 --- a/Platform/OpenCanopy/OpenCanopy.c +++ b/Platform/OpenCanopy/OpenCanopy.c @@ -1057,6 +1057,22 @@ GuiViewInitialize ( InitializeListHead (&DrawContext->Animations); } +VOID +GuiViewDeinitialize ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext + ) +{ + ZeroMem (DrawContext, sizeof (*DrawContext)); +} + +CONST GUI_SCREEN_CURSOR * +GuiViewCurrentCursor ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext + ) +{ + return &mScreenViewCursor; +} + VOID GuiGetBaseCoords ( IN GUI_OBJ *This, diff --git a/Platform/OpenCanopy/OpenCanopy.h b/Platform/OpenCanopy/OpenCanopy.h index 3298d942..d798c967 100644 --- a/Platform/OpenCanopy/OpenCanopy.h +++ b/Platform/OpenCanopy/OpenCanopy.h @@ -233,6 +233,16 @@ GuiViewInitialize ( IN VOID *GuiContext ); +VOID +GuiViewDeinitialize ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext + ); + +CONST GUI_SCREEN_CURSOR * +GuiViewCurrentCursor ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext + ); + VOID GuiDrawLoop ( IN OUT GUI_DRAWING_CONTEXT *DrawContext diff --git a/Platform/OpenCanopy/OpenCanopy.inf b/Platform/OpenCanopy/OpenCanopy.inf index 15c0c9a4..e3e986a0 100644 --- a/Platform/OpenCanopy/OpenCanopy.inf +++ b/Platform/OpenCanopy/OpenCanopy.inf @@ -56,6 +56,7 @@ gEfiSimplePointerProtocolGuid gEfiAbsolutePointerProtocolGuid gEfiUserInterfaceThemeProtocolGuid + gAppleEventProtocolGuid gOcBootstrapProtocolGuid gOcInterfaceProtocolGuid diff --git a/Platform/OpenCanopy/Views/BootPicker.c b/Platform/OpenCanopy/Views/BootPicker.c index 091ba85e..73f8da6b 100644 --- a/Platform/OpenCanopy/Views/BootPicker.c +++ b/Platform/OpenCanopy/Views/BootPicker.c @@ -976,36 +976,6 @@ InternalBootPickerEntryDestruct ( FreePool (Entry); } -VOID -BootPickerEntriesEmpty ( - VOID - ) -{ - LIST_ENTRY *ListEntry; - LIST_ENTRY *NextEntry; - GUI_VOLUME_ENTRY *BootEntry; - - ListEntry = mBootPicker.Hdr.Obj.Children.BackLink; - ASSERT (ListEntry == &mBootPickerSelector.Hdr.Link); - - // - // Last entry is always the selector, which is special and cannot be freed. - // - ListEntry = ListEntry->BackLink; - - while (!IsNull (&mBootPicker.Hdr.Obj.Children, ListEntry)) { - NextEntry = ListEntry->BackLink; - RemoveEntryList (ListEntry); - mBootPicker.Hdr.Obj.Width -= BOOT_ENTRY_WIDTH + BOOT_ENTRY_SPACE; - mBootPicker.Hdr.Obj.OffsetX += (BOOT_ENTRY_WIDTH + BOOT_ENTRY_SPACE) / 2; - - BootEntry = BASE_CR (ListEntry, GUI_VOLUME_ENTRY, Hdr.Link); - InternalBootPickerEntryDestruct (BootEntry); - - ListEntry = NextEntry; - } -} - BOOLEAN InternalBootPickerExitLoop ( IN VOID *Context @@ -1202,9 +1172,12 @@ BootPickerViewInitialize ( mBootPickerSelector.ClickImage = &GuiContext->Icons[ICON_SELECTOR][ICON_TYPE_BASE]; mBootPickerSelector.CurrentImage = &GuiContext->Icons[ICON_SELECTOR][ICON_TYPE_BASE]; + mBootPickerSelector.Hdr.Obj.OffsetX = 0; + mBootPickerSelector.Hdr.Obj.OffsetY = 0; mBootPicker.Hdr.Obj.OffsetX = mBootPickerView.Width / 2; mBootPicker.Hdr.Obj.OffsetY = (mBootPickerView.Height - mBootPicker.Hdr.Obj.Height) / 2; + mBootPicker.Hdr.Obj.Width = 0; // TODO: animations should be tied to UI objects, not global // Each object has its own list of animations. @@ -1215,17 +1188,21 @@ BootPickerViewInitialize ( // Conditions for delta function: // - InitBpAnimSinMov (GuiInterpolTypeSmooth, 0, 25); - STATIC GUI_ANIMATION PickerAnim; - PickerAnim.Context = NULL; - PickerAnim.Animate = InternalBootPickerAnimateSinMov; - InsertHeadList (&DrawContext->Animations, &PickerAnim.Link); + if (!GuiContext->DoneIntroAnimation) { + InitBpAnimSinMov (GuiInterpolTypeSmooth, 0, 25); + STATIC GUI_ANIMATION PickerAnim; + PickerAnim.Context = NULL; + PickerAnim.Animate = InternalBootPickerAnimateSinMov; + InsertHeadList (&DrawContext->Animations, &PickerAnim.Link); - InitBpAnimOpacity (GuiInterpolTypeSmooth, 0, 25); - STATIC GUI_ANIMATION PickerAnim2; - PickerAnim2.Context = NULL; - PickerAnim2.Animate = InternalBootPickerAnimateOpacity; - InsertHeadList (&DrawContext->Animations, &PickerAnim2.Link); + InitBpAnimOpacity (GuiInterpolTypeSmooth, 0, 25); + STATIC GUI_ANIMATION PickerAnim2; + PickerAnim2.Context = NULL; + PickerAnim2.Animate = InternalBootPickerAnimateOpacity; + InsertHeadList (&DrawContext->Animations, &PickerAnim2.Link); + + GuiContext->DoneIntroAnimation = TRUE; + } /* InitBpAnimImageList(GuiInterpolTypeLinear, 25, 25); @@ -1237,3 +1214,39 @@ BootPickerViewInitialize ( return RETURN_SUCCESS; } + +VOID +BootPickerViewDeinitialize ( + IN OUT GUI_DRAWING_CONTEXT *DrawContext, + IN OUT BOOT_PICKER_GUI_CONTEXT *GuiContext + ) +{ + LIST_ENTRY *ListEntry; + LIST_ENTRY *NextEntry; + GUI_VOLUME_ENTRY *BootEntry; + CONST GUI_SCREEN_CURSOR *ScreenCursor; + + ListEntry = mBootPicker.Hdr.Obj.Children.BackLink; + ASSERT (ListEntry == &mBootPickerSelector.Hdr.Link); + + // + // Last entry is always the selector, which is special and cannot be freed. + // + ListEntry = ListEntry->BackLink; + + while (!IsNull (&mBootPicker.Hdr.Obj.Children, ListEntry)) { + NextEntry = ListEntry->BackLink; + RemoveEntryList (ListEntry); + + BootEntry = BASE_CR (ListEntry, GUI_VOLUME_ENTRY, Hdr.Link); + InternalBootPickerEntryDestruct (BootEntry); + + ListEntry = NextEntry; + } + + ScreenCursor = GuiViewCurrentCursor (DrawContext); + GuiContext->CursorDefaultX = ScreenCursor->X; + GuiContext->CursorDefaultY = ScreenCursor->Y; + + GuiViewDeinitialize (DrawContext); +}