diff --git a/Platform/OpenCanopy/GuiIo.h b/Platform/OpenCanopy/GuiIo.h index 8abebfef36840daeb601d660d974b425b91d47cc..1a8f29eeb9b989b417343aa1a929ed102591b154 100644 --- a/Platform/OpenCanopy/GuiIo.h +++ b/Platform/OpenCanopy/GuiIo.h @@ -16,13 +16,6 @@ typedef struct GUI_OUTPUT_CONTEXT_ GUI_OUTPUT_CONTEXT; typedef struct GUI_POINTER_CONTEXT_ GUI_POINTER_CONTEXT; typedef struct GUI_KEY_CONTEXT_ GUI_KEY_CONTEXT; -typedef struct { - UINT32 X; - UINT32 Y; - BOOLEAN PrimaryDown; - BOOLEAN SecondaryDown; -} GUI_POINTER_STATE; - GUI_OUTPUT_CONTEXT * GuiOutputConstruct ( VOID @@ -53,10 +46,16 @@ GuiOutputDestruct ( IN GUI_OUTPUT_CONTEXT *Context ); +BOOLEAN +GuiPointerGetEvent ( + IN OUT GUI_POINTER_CONTEXT *Context, + OUT GUI_PTR_EVENT *Event + ); + VOID -GuiPointerGetState ( +GuiPointerGetPosition ( IN OUT GUI_POINTER_CONTEXT *Context, - OUT GUI_POINTER_STATE *State + OUT GUI_PTR_POSITION *Position ); VOID @@ -69,7 +68,8 @@ GuiPointerConstruct ( IN UINT32 DefaultX, IN UINT32 DefaultY, IN UINT32 Width, - IN UINT32 Height + IN UINT32 Height, + IN UINT8 UiScale ); VOID diff --git a/Platform/OpenCanopy/Input/InputSimAbsPtr.c b/Platform/OpenCanopy/Input/InputSimAbsPtr.c index 285ed63e19db6e0016f25d1927426b4347894cf4..75fa29e14a82c208995c0a657891eabdcd102a22 100644 --- a/Platform/OpenCanopy/Input/InputSimAbsPtr.c +++ b/Platform/OpenCanopy/Input/InputSimAbsPtr.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include @@ -20,16 +21,25 @@ #include "../OpenCanopy.h" #include "../GuiIo.h" +#define ABS_DOUBLE_CLICK_RADIUS 25U +#define IS_POWER_2(x) (((x) & ((x) - 1)) == 0 && (x) != 0) + struct GUI_POINTER_CONTEXT_ { APPLE_EVENT_PROTOCOL *AppleEvent; EFI_ABSOLUTE_POINTER_PROTOCOL *AbsPointer; APPLE_EVENT_HANDLE AppleEventHandle; UINT32 MaxX; UINT32 MaxY; - INT32 RawX; - INT32 RawY; - GUI_POINTER_STATE CurState; + GUI_PTR_POSITION RawPos; + GUI_PTR_POSITION CurPos; + GUI_PTR_POSITION AbsLastDownPos; + BOOLEAN AbsPrimaryDown; + BOOLEAN AbsDoubleClick; + UINT8 UiScale; UINT8 LockedBy; + UINT8 EventQueueHead; + UINT8 EventQueueTail; + GUI_PTR_EVENT EventQueue[16]; }; enum { @@ -38,6 +48,63 @@ enum { PointerLockedAbsolute }; +STATIC +VOID +InternalQueuePointerEvent ( + IN OUT GUI_POINTER_CONTEXT *Context, + IN UINT8 Type, + IN UINT32 X, + IN UINT32 Y + ) +{ + UINT32 Tail; + // + // Tail can be accessed concurrently, so increment atomically. + // Due to the modulus, wraparounds do not matter. The size of the queue must + // be a power of two for this to hold. + // + STATIC_ASSERT ( + IS_POWER_2 (ARRAY_SIZE (Context->EventQueue)), + "The pointer event queue must have a power of two length." + ); + + Tail = OcAtomicPreIncUint8 (&Context->EventQueueTail) % ARRAY_SIZE (Context->EventQueue); + Context->EventQueue[Tail].Type = Type; + Context->EventQueue[Tail].Pos.Pos.X = X; + Context->EventQueue[Tail].Pos.Pos.Y = Y; +} + +BOOLEAN +GuiPointerGetEvent ( + IN OUT GUI_POINTER_CONTEXT *Context, + OUT GUI_PTR_EVENT *Event + ) +{ + // + // EventQueueHead cannot be accessed concurrently. + // + if (Context->EventQueueHead == Context->EventQueueTail) { + return FALSE; + } + + CopyMem ( + Event, + &Context->EventQueue[Context->EventQueueHead % ARRAY_SIZE (Context->EventQueue)], + sizeof (*Event) + ); + // + // Due to the modulus, wraparounds do not matter. The size of the queue must + // be a power of two for this to hold. + // + STATIC_ASSERT ( + IS_POWER_2 (ARRAY_SIZE (Context->EventQueue)), + "The pointer event queue must have a power of two length." + ); + ++Context->EventQueueHead; + + return TRUE; +} + STATIC VOID EFIAPI @@ -48,8 +115,8 @@ InternalAppleEventNotification ( { APPLE_POINTER_EVENT_TYPE EventType; GUI_POINTER_CONTEXT *Context; - INT32 NewX; - INT32 NewY; + GUI_PTR_POSITION NewPos; + GUI_PTR_POSITION NewRaw; INT64 NewCoord; Context = NotifyContext; @@ -62,12 +129,6 @@ InternalAppleEventNotification ( return; } - if ((Context->CurState.PrimaryDown | Context->CurState.SecondaryDown) == 0) { - ASSERT (Context->LockedBy == PointerUnlocked); - } else { - ASSERT (Context->LockedBy == PointerLockedSimple); - } - EventType = Information->EventData.PointerEventType; if ((EventType & APPLE_EVENT_TYPE_MOUSE_MOVED) != 0) { @@ -75,49 +136,63 @@ InternalAppleEventNotification ( // Use a factor of 2 for pointer acceleration. // - NewX = Information->PointerPosition.Horizontal; + NewRaw.Pos.X = (UINT32) Information->PointerPosition.Horizontal; - NewCoord = (INT64) Context->CurState.X + 2 * ((INT64) NewX - Context->RawX); + NewCoord = (INT64) Context->CurPos.Pos.X + 2 * ((INT64) NewRaw.Pos.X - Context->RawPos.Pos.X); if (NewCoord < 0) { - NewCoord = 0; + NewPos.Pos.X = 0; } else if (NewCoord > Context->MaxX) { - NewCoord = Context->MaxX; + NewPos.Pos.X = Context->MaxX; + } else { + NewPos.Pos.X = (UINT32) NewCoord; } - Context->CurState.X = (UINT32) NewCoord; - Context->RawX = NewX; + NewRaw.Pos.Y = (UINT32) Information->PointerPosition.Vertical; - NewY = Information->PointerPosition.Vertical; - - NewCoord = (INT64) Context->CurState.Y + 2 * ((INT64) NewY - Context->RawY); + NewCoord = (INT64) Context->CurPos.Pos.Y + 2 * ((INT64) NewRaw.Pos.Y - Context->RawPos.Pos.Y); if (NewCoord < 0) { - NewCoord = 0; + NewPos.Pos.Y = 0; } else if (NewCoord > Context->MaxY) { - NewCoord = Context->MaxY; + NewPos.Pos.Y = Context->MaxY; + } else { + NewPos.Pos.Y = (UINT32) NewCoord; } - Context->CurState.Y = (UINT32) NewCoord; - Context->RawY = NewY; + Context->CurPos.Uint64 = NewPos.Uint64; + Context->RawPos.Uint64 = NewRaw.Uint64; } if ((EventType & APPLE_EVENT_TYPE_MOUSE_DOWN) != 0) { if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) { - Context->CurState.PrimaryDown = TRUE; - } else if ((EventType & APPLE_EVENT_TYPE_RIGHT_BUTTON) != 0) { - Context->CurState.SecondaryDown = TRUE; + ASSERT (Context->LockedBy == PointerUnlocked); + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryDown, + Context->CurPos.Pos.X, + Context->CurPos.Pos.Y + ); + Context->LockedBy = PointerLockedSimple; } } else if ((EventType & APPLE_EVENT_TYPE_MOUSE_UP) != 0) { if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) { - Context->CurState.PrimaryDown = FALSE; - } else if ((EventType & APPLE_EVENT_TYPE_RIGHT_BUTTON) != 0) { - Context->CurState.SecondaryDown = FALSE; + ASSERT (Context->LockedBy == PointerLockedSimple); + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryUp, + Context->CurPos.Pos.X, + Context->CurPos.Pos.Y + ); + Context->LockedBy = PointerUnlocked; + } + } else if ((EventType & APPLE_EVENT_TYPE_MOUSE_DOUBLE_CLICK) != 0) { + if ((EventType & APPLE_EVENT_TYPE_LEFT_BUTTON) != 0) { + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryDoubleClick, + Context->CurPos.Pos.X, + Context->CurPos.Pos.Y + ); } - } - - if ((Context->CurState.PrimaryDown | Context->CurState.SecondaryDown) == 0) { - Context->LockedBy = PointerUnlocked; - } else { - Context->LockedBy = PointerLockedSimple; } } @@ -131,6 +206,7 @@ InternalUpdateContextAbsolute ( EFI_ABSOLUTE_POINTER_STATE PointerState; UINT64 NewX; UINT64 NewY; + GUI_PTR_POSITION NewPos; ASSERT (Context != NULL); @@ -144,12 +220,6 @@ InternalUpdateContextAbsolute ( return; } - if ((Context->CurState.PrimaryDown | Context->CurState.SecondaryDown) == 0) { - ASSERT (Context->LockedBy == PointerUnlocked); - } else { - ASSERT (Context->LockedBy == PointerLockedAbsolute); - } - Status = Context->AbsPointer->GetState (Context->AbsPointer, &PointerState); if (EFI_ERROR (Status)) { return; @@ -157,27 +227,69 @@ InternalUpdateContextAbsolute ( NewX = PointerState.CurrentX - Context->AbsPointer->Mode->AbsoluteMinX; NewX *= Context->MaxX + 1; - Context->CurState.X = (UINT32) DivU64x32 ( + NewPos.Pos.X = (UINT32) DivU64x32 ( NewX, (UINT32) (Context->AbsPointer->Mode->AbsoluteMaxX - Context->AbsPointer->Mode->AbsoluteMinX) ); - Context->RawX = (INT32) Context->CurState.X; NewY = PointerState.CurrentY - Context->AbsPointer->Mode->AbsoluteMinY; NewY *= Context->MaxY + 1; - Context->CurState.Y = (UINT32) DivU64x32 ( + NewPos.Pos.Y = (UINT32) DivU64x32 ( NewY, (UINT32) (Context->AbsPointer->Mode->AbsoluteMaxY - Context->AbsPointer->Mode->AbsoluteMinY) ); - Context->RawY = (INT32) Context->CurState.Y; + // + // This is not perfectly concurrent, but good enough. + // + Context->CurPos.Uint64 = NewPos.Uint64; + Context->RawPos.Uint64 = NewPos.Uint64; + // + // Cancel double click when the finger is moved too far away. + // + if (Context->AbsDoubleClick) { + if (ABS ((INT64) NewPos.Pos.X - Context->AbsLastDownPos.Pos.X) > ABS_DOUBLE_CLICK_RADIUS * Context->UiScale + || ABS ((INT64) NewPos.Pos.Y - Context->AbsLastDownPos.Pos.Y) > ABS_DOUBLE_CLICK_RADIUS * Context->UiScale) { + Context->AbsDoubleClick = FALSE; + } + } - Context->CurState.PrimaryDown = (PointerState.ActiveButtons & EFI_ABSP_TouchActive) != 0; - Context->CurState.SecondaryDown = (PointerState.ActiveButtons & EFI_ABS_AltActive) != 0; + if (Context->AbsPrimaryDown != ((PointerState.ActiveButtons & EFI_ABSP_TouchActive) != 0)) { + Context->AbsPrimaryDown = ((PointerState.ActiveButtons & EFI_ABSP_TouchActive) != 0); + if (Context->AbsPrimaryDown) { + ASSERT (Context->LockedBy == PointerUnlocked); + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryDown, + NewPos.Pos.X, + NewPos.Pos.Y + ); + Context->LockedBy = PointerLockedAbsolute; - if ((Context->CurState.PrimaryDown | Context->CurState.SecondaryDown) == 0) { - Context->LockedBy = PointerUnlocked; - } else { - Context->LockedBy = PointerLockedAbsolute; + Context->AbsLastDownPos.Pos.X = NewPos.Pos.X; + Context->AbsLastDownPos.Pos.Y = NewPos.Pos.Y; + Context->AbsDoubleClick = TRUE; + } else { + ASSERT (Context->LockedBy == PointerLockedAbsolute); + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryUp, + NewPos.Pos.X, + NewPos.Pos.Y + ); + Context->LockedBy = PointerUnlocked; + + ASSERT (Context->UiScale > 0); + + if (Context->AbsDoubleClick) { + InternalQueuePointerEvent ( + Context, + GuiPointerPrimaryDoubleClick, + NewPos.Pos.X, + NewPos.Pos.Y + ); + Context->AbsDoubleClick = FALSE; + } + } } } @@ -198,32 +310,34 @@ GuiPointerReset ( } VOID -GuiPointerGetState ( +GuiPointerGetPosition ( IN OUT GUI_POINTER_CONTEXT *Context, - OUT GUI_POINTER_STATE *State + OUT GUI_PTR_POSITION *Position ) { EFI_TPL OldTpl; ASSERT (Context != NULL); - ASSERT (State != NULL); + ASSERT (Position != NULL); // // Prevent simple pointer updates during state retrieval. + // On 64+-bit systems, the operation is atomic. // - OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + if (sizeof (UINTN) < sizeof (UINT64)) { + OldTpl = gBS->RaiseTPL (TPL_NOTIFY); + } // // The simple pointer updates are done in InternalAppleEventNotification(). // InternalUpdateContextAbsolute (Context); // - // Return the current pointer state. + // Return the current pointer position. // - State->X = Context->CurState.X; - State->Y = Context->CurState.Y; - State->PrimaryDown = Context->CurState.PrimaryDown; - State->SecondaryDown = Context->CurState.SecondaryDown; + Position->Uint64 = Context->CurPos.Uint64; - gBS->RestoreTPL (OldTpl); + if (sizeof (UINTN) < sizeof (UINT64)) { + gBS->RestoreTPL (OldTpl); + } } GUI_POINTER_CONTEXT * @@ -231,7 +345,8 @@ GuiPointerConstruct ( IN UINT32 DefaultX, IN UINT32 DefaultY, IN UINT32 Width, - IN UINT32 Height + IN UINT32 Height, + IN UINT8 UiScale ) { // TODO: alloc on the fly? @@ -246,12 +361,13 @@ GuiPointerConstruct ( ASSERT (Width <= MAX_INT32); ASSERT (Height <= MAX_INT32); - Context.MaxX = Width - 1; - Context.MaxY = Height - 1; - Context.CurState.X = DefaultX; - Context.CurState.Y = DefaultY; - Context.RawX = (INT32) DefaultX; - Context.RawY = (INT32) DefaultY; + Context.MaxX = Width - 1; + Context.MaxY = Height - 1; + Context.CurPos.Pos.X = DefaultX; + Context.CurPos.Pos.Y = DefaultY; + Context.RawPos.Pos.X = DefaultX; + Context.RawPos.Pos.Y = DefaultY; + Context.UiScale = UiScale; Status = OcHandleProtocolFallback ( gST->ConsoleInHandle, diff --git a/Platform/OpenCanopy/OcBootstrap.c b/Platform/OpenCanopy/OcBootstrap.c index b597c6fc13d39a93e76b9bc2b898e8438c80d13f..f4d0c43508e4783a5c846f424474b70ec828bd5c 100644 --- a/Platform/OpenCanopy/OcBootstrap.c +++ b/Platform/OpenCanopy/OcBootstrap.c @@ -38,13 +38,13 @@ STATIC EFI_CONSOLE_CONTROL_SCREEN_MODE mPreviousMode; STATIC EFI_STATUS OcShowMenuByOcEnter ( - IN OC_BOOT_CONTEXT *BootContext + IN BOOT_PICKER_GUI_CONTEXT *GuiContext ) { EFI_STATUS Status; Status = GuiLibConstruct ( - BootContext->PickerContext, + GuiContext, mGuiContext.CursorDefaultX, mGuiContext.CursorDefaultY ); @@ -94,7 +94,7 @@ OcShowMenuByOc ( mGuiContext.PickerContext = BootContext->PickerContext; mGuiContext.AudioPlaybackTimeout = -1; - Status = OcShowMenuByOcEnter (BootContext); + Status = OcShowMenuByOcEnter (&mGuiContext); if (EFI_ERROR (Status)) { return Status; } diff --git a/Platform/OpenCanopy/OpenCanopy.c b/Platform/OpenCanopy/OpenCanopy.c index 6e1ece4ea556977fa7cb41e40971f0a0c3224888..603d14f6ba1f397bd77ccf42024e2e77fb9cb12f 100644 --- a/Platform/OpenCanopy/OpenCanopy.c +++ b/Platform/OpenCanopy/OpenCanopy.c @@ -209,11 +209,9 @@ GuiObjDelegatePtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { UINTN Index; @@ -221,18 +219,20 @@ GuiObjDelegatePtrEvent ( GUI_OBJ_CHILD *Child; ASSERT (This != NULL); - ASSERT (This->Width > OffsetX); - ASSERT (This->Height > OffsetY); + ASSERT (Event->Pos.Pos.X >= BaseX); + ASSERT (Event->Pos.Pos.Y >= BaseY); + ASSERT (This->Width > Event->Pos.Pos.X - BaseX); + ASSERT (This->Height > Event->Pos.Pos.Y - BaseY); ASSERT (DrawContext != NULL); // // Pointer event propagation is backwards due to forwards draw order. // for (Index = This->NumChildren; Index > 0; --Index) { Child = This->Children[Index - 1]; - if (OffsetX < Child->Obj.OffsetX - || OffsetX >= Child->Obj.OffsetX + Child->Obj.Width - || OffsetY < Child->Obj.OffsetY - || OffsetY >= Child->Obj.OffsetY + Child->Obj.Height) { + if (Event->Pos.Pos.X - BaseX < Child->Obj.OffsetX + || Event->Pos.Pos.X - BaseX >= Child->Obj.OffsetX + Child->Obj.Width + || Event->Pos.Pos.Y - BaseY < Child->Obj.OffsetY + || Event->Pos.Pos.Y - BaseY >= Child->Obj.OffsetY + Child->Obj.Height) { continue; } @@ -241,11 +241,9 @@ GuiObjDelegatePtrEvent ( &Child->Obj, DrawContext, Context, - Event, - BaseX + Child->Obj.OffsetX, - BaseY + Child->Obj.OffsetY, - OffsetX - Child->Obj.OffsetX, - OffsetY - Child->Obj.OffsetY + BaseX + Child->Obj.OffsetX, + BaseY + Child->Obj.OffsetY, + Event ); if (Obj != NULL) { return Obj; @@ -592,17 +590,17 @@ GuiOverlayPointer ( IN OUT GUI_DRAWING_CONTEXT *DrawContext ) { - CONST GUI_IMAGE *CursorImage; - UINT32 MaxWidth; - UINT32 MaxHeight; - GUI_POINTER_STATE PointerState; - - INT64 BaseX; - INT64 BaseY; - UINT32 ImageOffsetX; - UINT32 ImageOffsetY; - UINT32 DrawBaseX; - UINT32 DrawBaseY; + CONST GUI_IMAGE *CursorImage; + UINT32 MaxWidth; + UINT32 MaxHeight; + GUI_PTR_POSITION PointerPos; + + INT64 BaseX; + INT64 BaseY; + UINT32 ImageOffsetX; + UINT32 ImageOffsetY; + UINT32 DrawBaseX; + UINT32 DrawBaseY; ASSERT (DrawContext != NULL); @@ -612,10 +610,10 @@ GuiOverlayPointer ( // // Poll the current cursor position late to reduce input lag. // - GuiPointerGetState (mPointerContext, &PointerState); + GuiPointerGetPosition (mPointerContext, &PointerPos); - ASSERT (PointerState.X < DrawContext->Screen->Width); - ASSERT (PointerState.Y < DrawContext->Screen->Height); + ASSERT (PointerPos.Pos.X < DrawContext->Screen->Width); + ASSERT (PointerPos.Pos.Y < DrawContext->Screen->Height); // // Unconditionally draw the cursor to increase frametime consistency and @@ -629,7 +627,7 @@ GuiOverlayPointer ( // Draw the new cursor at the new position. // - BaseX = (INT64) PointerState.X - BOOT_CURSOR_OFFSET * DrawContext->Scale; + BaseX = (INT64) PointerPos.Pos.X - BOOT_CURSOR_OFFSET * DrawContext->Scale; if (BaseX < 0) { ImageOffsetX = (UINT32) -BaseX; DrawBaseX = 0; @@ -640,7 +638,7 @@ GuiOverlayPointer ( MaxWidth = MIN (CursorImage->Width, (UINT32) (DrawContext->Screen->Width - BaseX)); - BaseY = (INT64) PointerState.Y - BOOT_CURSOR_OFFSET * DrawContext->Scale; + BaseY = (INT64) PointerPos.Pos.Y - BOOT_CURSOR_OFFSET * DrawContext->Scale; if (BaseY < 0) { ImageOffsetY = (UINT32) -BaseY; DrawBaseY = 0; @@ -792,9 +790,9 @@ GuiRedrawAndFlushScreen ( EFI_STATUS GuiLibConstruct ( - IN OC_PICKER_CONTEXT *PickerContext, - IN UINT32 CursorDefaultX, - IN UINT32 CursorDefaultY + IN BOOT_PICKER_GUI_CONTEXT *GuiContext, + IN UINT32 CursorDefaultX, + IN UINT32 CursorDefaultY ) { CONST EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *OutputInfo; @@ -811,19 +809,20 @@ GuiLibConstruct ( CursorDefaultX = MIN (CursorDefaultX, OutputInfo->HorizontalResolution - 1); CursorDefaultY = MIN (CursorDefaultY, OutputInfo->VerticalResolution - 1); - if ((PickerContext->PickerAttributes & OC_ATTR_USE_POINTER_CONTROL) != 0) { + if ((GuiContext->PickerContext->PickerAttributes & OC_ATTR_USE_POINTER_CONTROL) != 0) { mPointerContext = GuiPointerConstruct ( CursorDefaultX, CursorDefaultY, OutputInfo->HorizontalResolution, - OutputInfo->VerticalResolution + OutputInfo->VerticalResolution, + GuiContext->Scale ); if (mPointerContext == NULL) { DEBUG ((DEBUG_WARN, "OCUI: Failed to initialise pointer\n")); } } - mKeyContext = GuiKeyConstruct (PickerContext); + mKeyContext = GuiKeyConstruct (GuiContext->PickerContext); if (mKeyContext == NULL) { DEBUG ((DEBUG_WARN, "OCUI: Failed to initialise key input\n")); } @@ -911,12 +910,12 @@ GuiViewDeinitialize ( OUT BOOT_PICKER_GUI_CONTEXT *GuiContext ) { - GUI_POINTER_STATE PointerState; + GUI_PTR_POSITION PointerPos; if (mPointerContext != NULL) { - GuiPointerGetState (mPointerContext, &PointerState); - GuiContext->CursorDefaultX = PointerState.X; - GuiContext->CursorDefaultY = PointerState.Y; + GuiPointerGetPosition (mPointerContext, &PointerPos); + GuiContext->CursorDefaultX = PointerPos.Pos.X; + GuiContext->CursorDefaultY = PointerPos.Pos.Y; } ZeroMem (DrawContext, sizeof (*DrawContext)); @@ -974,31 +973,35 @@ GuiDrawLoop ( IN UINT32 TimeOutSeconds ) { - EFI_STATUS Status; - BOOLEAN Result; - - INTN InputKey; - BOOLEAN Modifier; - GUI_POINTER_STATE PointerState; - GUI_OBJ *HoldObject; - INT64 HoldObjBaseX; - INT64 HoldObjBaseY; - CONST LIST_ENTRY *AnimEntry; - CONST GUI_ANIMATION *Animation; - UINT64 LoopStartTsc; - UINT64 LastTsc; - UINT64 NewLastTsc; - BOOLEAN ObjectHeld; - - CONST GUI_IMAGE *CursorImage; - UINT64 FrameTime; + EFI_STATUS Status; + BOOLEAN Result; + + INTN InputKey; + BOOLEAN Modifier; + GUI_PTR_EVENT PointerEvent; + GUI_OBJ *TempObject; + GUI_OBJ *HoldObject; + INT64 HoldObjBaseX; + INT64 HoldObjBaseY; + CONST LIST_ENTRY *AnimEntry; + CONST GUI_ANIMATION *Animation; + UINT64 LoopStartTsc; + UINT64 LastTsc; + UINT64 NewLastTsc; + BOOLEAN ObjectHeld; + + CONST GUI_IMAGE *CursorImage; + UINT64 FrameTime; ASSERT (DrawContext != NULL); mNumValidDrawReqs = 0; FrameTime = 0; HoldObject = NULL; - ObjectHeld = FALSE; + + DEBUG_CODE_BEGIN (); + ObjectHeld = FALSE; + DEBUG_CODE_END (); // // Clear previous inputs. @@ -1038,29 +1041,65 @@ GuiDrawLoop ( // // Process pointer events. // - GuiPointerGetState (mPointerContext, &PointerState); - - if (PointerState.PrimaryDown) { - if (!ObjectHeld && HoldObject == NULL) { - HoldObject = GuiObjDelegatePtrEvent ( - DrawContext->Screen, - DrawContext, - DrawContext->GuiContext, - GuiPointerPrimaryDown, - 0, - 0, - PointerState.X, - PointerState.Y - ); - - } - - ObjectHeld = TRUE; - } else { - ObjectHeld = FALSE; - } + Result = GuiPointerGetEvent (mPointerContext, &PointerEvent); + if (Result) { + if (PointerEvent.Type == GuiPointerPrimaryUp) { + // + // 'Button down' must have caught and set an interaction object. + // It may be NULL for objects that solely delegate pointer events. + // + ASSERT (ObjectHeld); + + if (HoldObject != NULL) { + GuiGetBaseCoords ( + HoldObject, + DrawContext, + &HoldObjBaseX, + &HoldObjBaseY + ); + HoldObject->PtrEvent ( + HoldObject, + DrawContext, + DrawContext->GuiContext, + HoldObjBaseX, + HoldObjBaseY, + &PointerEvent + ); + HoldObject = NULL; + } - if (HoldObject != NULL) { + DEBUG_CODE_BEGIN (); + ObjectHeld = FALSE; + DEBUG_CODE_END (); + } else { + // + // HoldObject == NULL cannot be tested here as double-click may arrive + // before button up. + // + ASSERT (PointerEvent.Type != GuiPointerPrimaryUp); + TempObject = GuiObjDelegatePtrEvent ( + DrawContext->Screen, + DrawContext, + DrawContext->GuiContext, + 0, + 0, + &PointerEvent + ); + if (PointerEvent.Type == GuiPointerPrimaryDown) { + DEBUG_CODE_BEGIN (); + ObjectHeld = TRUE; + DEBUG_CODE_END (); + + HoldObject = TempObject; + } + } + } else if (HoldObject != NULL) { + // + // If there are no events to process, update the cursor position with + // the interaction object for visual effects. + // + PointerEvent.Type = GuiPointerPrimaryDown; + GuiPointerGetPosition (mPointerContext, &PointerEvent.Pos); GuiGetBaseCoords ( HoldObject, DrawContext, @@ -1068,18 +1107,13 @@ GuiDrawLoop ( &HoldObjBaseY ); HoldObject->PtrEvent ( - HoldObject, - DrawContext, - DrawContext->GuiContext, - !PointerState.PrimaryDown ? GuiPointerPrimaryUp : GuiPointerPrimaryHold, - HoldObjBaseX, - HoldObjBaseY, - (INT64)PointerState.X - HoldObjBaseX, - (INT64)PointerState.Y - HoldObjBaseY - ); - if (!PointerState.PrimaryDown) { - HoldObject = NULL; - } + HoldObject, + DrawContext, + DrawContext->GuiContext, + HoldObjBaseX, + HoldObjBaseY, + &PointerEvent + ); } } diff --git a/Platform/OpenCanopy/OpenCanopy.h b/Platform/OpenCanopy/OpenCanopy.h index 183eaa1aa92adaa0f9eee114f953c094dba71f19..4e9e9308cbd58c53b23e2fee969e83428f8f2d8c 100644 --- a/Platform/OpenCanopy/OpenCanopy.h +++ b/Platform/OpenCanopy/OpenCanopy.h @@ -20,11 +20,23 @@ typedef struct _BOOT_PICKER_GUI_CONTEXT BOOT_PICKER_GUI_CONTEXT; enum { GuiPointerPrimaryDown, - GuiPointerPrimaryHold, - GuiPointerPrimaryUp + GuiPointerPrimaryUp, + GuiPointerPrimaryDoubleClick }; -typedef UINT8 GUI_PTR_EVENT; +typedef union { + struct { + UINT32 X; + UINT32 Y; + } Pos; + UINT64 Uint64; +} GUI_PTR_POSITION; + + +typedef struct { + UINT8 Type; + GUI_PTR_POSITION Pos; +} GUI_PTR_EVENT; typedef VOID @@ -46,11 +58,9 @@ GUI_OBJ * IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ); typedef @@ -181,11 +191,9 @@ GuiObjDelegatePtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ); BOOLEAN @@ -271,9 +279,9 @@ GuiClearScreen ( EFI_STATUS GuiLibConstruct ( - IN OC_PICKER_CONTEXT *PickerContext, - IN UINT32 CursorDefaultX, - IN UINT32 CursorDefaultY + IN BOOT_PICKER_GUI_CONTEXT *GuiContext, + IN UINT32 CursorDefaultX, + IN UINT32 CursorDefaultY ); VOID diff --git a/Platform/OpenCanopy/Views/BootPicker.c b/Platform/OpenCanopy/Views/BootPicker.c index 627d22881584cf69cdcb7db1d6c0eb924fc3f5e1..cc60853066e9f51f55ff4bfeb7f957d06a77618f 100644 --- a/Platform/OpenCanopy/Views/BootPicker.c +++ b/Platform/OpenCanopy/Views/BootPicker.c @@ -473,24 +473,22 @@ InternalBootPickerEntryPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { - STATIC BOOLEAN SameIter = FALSE; - GUI_VOLUME_ENTRY *Entry; BOOLEAN IsHit; + UINT32 OffsetX; + UINT32 OffsetY; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); - if (Event == GuiPointerPrimaryHold) { - return This; - } + OffsetX = (UINT32) (Event->Pos.Pos.X - BaseX); + OffsetY = (UINT32) (Event->Pos.Pos.Y - BaseY); + + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); if (OffsetX < BOOT_ENTRY_ICON_SPACE * DrawContext->Scale || OffsetY < BOOT_ENTRY_ICON_SPACE * DrawContext->Scale) { @@ -508,7 +506,7 @@ InternalBootPickerEntryPtrEvent ( return This; } - if (Event == GuiPointerPrimaryDown) { + if (Event->Type == GuiPointerPrimaryDown) { if (mBootPicker.SelectedIndex != Entry->Index) { ASSERT (Entry->Hdr.Parent == &mBootPicker.Hdr.Obj); InternalBootPickerChangeEntry ( @@ -518,21 +516,16 @@ InternalBootPickerEntryPtrEvent ( BaseY - This->OffsetY, Entry->Index ); - SameIter = TRUE; } - } else { + } else if (Event->Type == GuiPointerPrimaryDoubleClick) { // // This must be ensured because the UI directs Move/Up events to the object // Down had been sent to. // ASSERT (mBootPicker.SelectedIndex == Entry->Index); - if (SameIter) { - SameIter = FALSE; - } else { - Context->ReadyToBoot = TRUE; - ASSERT (Context->BootEntry == Entry->Context); - } + Context->ReadyToBoot = TRUE; + ASSERT (Context->BootEntry == Entry->Context); } // // There should be no children. @@ -724,17 +717,17 @@ InternalBootPickerSelectorPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { GUI_OBJ_CLICKABLE *Clickable; CONST GUI_IMAGE *ButtonImage; BOOLEAN IsHit; + UINT32 OffsetX; + UINT32 OffsetY; ASSERT (This != NULL); ASSERT (DrawContext != NULL); @@ -744,12 +737,15 @@ InternalBootPickerSelectorPtrEvent ( // ASSERT (This->NumChildren == 0); + OffsetX = (UINT32) (Event->Pos.Pos.X - BaseX); + OffsetY = (UINT32) (Event->Pos.Pos.Y - BaseY); + Clickable = BASE_CR (This, GUI_OBJ_CLICKABLE, Hdr.Obj); ButtonImage = &Context->Icons[ICON_SELECTOR][ICON_TYPE_BASE]; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); if (OffsetX >= (BOOT_SELECTOR_BACKGROUND_DIMENSION * DrawContext->Scale - ButtonImage->Width) / 2 && OffsetY >= (BOOT_SELECTOR_BACKGROUND_DIMENSION + BOOT_SELECTOR_BUTTON_SPACE) * DrawContext->Scale) { IsHit = GuiClickableIsHit ( @@ -758,7 +754,7 @@ InternalBootPickerSelectorPtrEvent ( OffsetY - (BOOT_SELECTOR_BACKGROUND_DIMENSION + BOOT_SELECTOR_BUTTON_SPACE) * DrawContext->Scale ); if (IsHit) { - if (Event == GuiPointerPrimaryUp) { + if (Event->Type == GuiPointerPrimaryUp) { ASSERT (Context->BootEntry == InternalGetVolumeEntry (mBootPicker.SelectedIndex)->Context); Context->ReadyToBoot = TRUE; } else { @@ -787,11 +783,9 @@ InternalBootPickerLeftScrollPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { GUI_OBJ_CLICKABLE *Clickable; @@ -812,19 +806,19 @@ InternalBootPickerLeftScrollPtrEvent ( Clickable = BASE_CR (This, GUI_OBJ_CLICKABLE, Hdr.Obj); ButtonImage = &Context->Icons[ICON_LEFT][ICON_TYPE_BASE]; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); ASSERT (ButtonImage->Width == This->Width); ASSERT (ButtonImage->Height == This->Height); IsHit = GuiClickableIsHit ( ButtonImage, - OffsetX, - OffsetY + Event->Pos.Pos.X - BaseX, + Event->Pos.Pos.Y - BaseY ); if (IsHit) { - if (Event != GuiPointerPrimaryUp) { + if (Event->Type == GuiPointerPrimaryDown) { ButtonImage = &Context->Icons[ICON_LEFT][ICON_TYPE_HELD]; } else if (mBootPicker.Hdr.Obj.OffsetX < 0) { // @@ -891,11 +885,9 @@ InternalBootPickerRightScrollPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { GUI_OBJ_CLICKABLE *Clickable; @@ -916,17 +908,17 @@ InternalBootPickerRightScrollPtrEvent ( Clickable = BASE_CR (This, GUI_OBJ_CLICKABLE, Hdr.Obj); ButtonImage = &Context->Icons[ICON_RIGHT][ICON_TYPE_BASE]; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); IsHit = GuiClickableIsHit ( ButtonImage, - OffsetX, - OffsetY + Event->Pos.Pos.X - BaseX, + Event->Pos.Pos.Y - BaseY ); if (IsHit) { - if (Event != GuiPointerPrimaryUp) { + if (Event->Type == GuiPointerPrimaryDown) { ButtonImage = &Context->Icons[ICON_RIGHT][ICON_TYPE_HELD]; } else if (mBootPicker.Hdr.Obj.OffsetX + mBootPicker.Hdr.Obj.Width > mBootPickerContainer.Obj.Width) { // @@ -1038,11 +1030,9 @@ InternalBootPickerShutDownPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { GUI_OBJ_CLICKABLE *Clickable; @@ -1052,17 +1042,17 @@ InternalBootPickerShutDownPtrEvent ( Clickable = BASE_CR (This, GUI_OBJ_CLICKABLE, Hdr.Obj); ButtonImage = &Context->Icons[ICON_SHUT_DOWN][ICON_TYPE_BASE]; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); IsHit = GuiClickableIsHit ( ButtonImage, - OffsetX, - OffsetY + Event->Pos.Pos.X - BaseX, + Event->Pos.Pos.Y - BaseY ); if (IsHit) { - if (Event != GuiPointerPrimaryUp) { + if (Event->Type == GuiPointerPrimaryDown) { ButtonImage = &Context->Icons[ICON_SHUT_DOWN][ICON_TYPE_HELD]; } else { gRT->ResetSystem (EfiResetShutdown, EFI_SUCCESS, 0, NULL); @@ -1090,11 +1080,9 @@ InternalBootPickerRestartPtrEvent ( IN OUT GUI_OBJ *This, IN OUT GUI_DRAWING_CONTEXT *DrawContext, IN BOOT_PICKER_GUI_CONTEXT *Context, - IN GUI_PTR_EVENT Event, IN INT64 BaseX, IN INT64 BaseY, - IN INT64 OffsetX, - IN INT64 OffsetY + IN CONST GUI_PTR_EVENT *Event ) { GUI_OBJ_CLICKABLE *Clickable; @@ -1104,17 +1092,17 @@ InternalBootPickerRestartPtrEvent ( Clickable = BASE_CR (This, GUI_OBJ_CLICKABLE, Hdr.Obj); ButtonImage = &Context->Icons[ICON_RESTART][ICON_TYPE_BASE]; - ASSERT (Event == GuiPointerPrimaryDown - || Event == GuiPointerPrimaryHold - || Event == GuiPointerPrimaryUp); + ASSERT (Event->Type == GuiPointerPrimaryDown + || Event->Type == GuiPointerPrimaryUp + || Event->Type == GuiPointerPrimaryDoubleClick); IsHit = GuiClickableIsHit ( ButtonImage, - OffsetX, - OffsetY + Event->Pos.Pos.X - BaseX, + Event->Pos.Pos.Y - BaseY ); if (IsHit) { - if (Event != GuiPointerPrimaryUp) { + if (Event->Type == GuiPointerPrimaryDown) { ButtonImage = &Context->Icons[ICON_RESTART][ICON_TYPE_HELD]; } else { gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);