311 lines
10 KiB
C
311 lines
10 KiB
C
/** @file
|
|
Setup Mouse Cursor implementation
|
|
|
|
;******************************************************************************
|
|
;* Copyright (c) 2012 - 2020, Insyde Software Corp. All Rights Reserved.
|
|
;*
|
|
;* You may not reproduce, distribute, publish, display, perform, modify, adapt,
|
|
;* transmit, broadcast, present, recite, release, license or otherwise exploit
|
|
;* any part of this publication in any form, by any means, without the prior
|
|
;* written permission of Insyde Software Corporation.
|
|
;*
|
|
;******************************************************************************
|
|
|
|
*/
|
|
|
|
#include "SetupMouse.h"
|
|
#include <Library/UefiHiiServicesLib.h>
|
|
extern EFI_HII_HANDLE mImageHiiHandle;
|
|
|
|
/**
|
|
Initialize cursor data
|
|
|
|
@param[in, out] Private PRIVATE_MOUSE_DATA
|
|
|
|
@retval EFI_SUCCESS Initialize success
|
|
**/
|
|
EFI_STATUS
|
|
InitializeCursor (
|
|
IN OUT PRIVATE_MOUSE_DATA *Private
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
EFI_IMAGE_INPUT Image;
|
|
|
|
if (mImageHiiHandle == NULL) {
|
|
return EFI_NOT_READY;
|
|
}
|
|
|
|
Status = gHiiImage->GetImage (
|
|
gHiiImage,
|
|
mImageHiiHandle,
|
|
IMAGE_TOKEN (IMAGE_CURSOR),
|
|
&Image
|
|
);
|
|
if (EFI_ERROR (Status) || Image.Bitmap == NULL) {
|
|
return Status;
|
|
}
|
|
if ((Image.Flags & H2O_IMAGE_ALPHA_CHANNEL) != H2O_IMAGE_ALPHA_CHANNEL) {
|
|
ConvertToAlphaChannelImage (&Image);
|
|
}
|
|
|
|
SetRect (&Private->Cursor.ImageRc, 0, 0, Image.Width, Image.Height);
|
|
Private->Cursor.Image = Image.Bitmap;
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
Destroy cursor data
|
|
|
|
@param[in, out] Private PRIVATE_MOUSE_DATA
|
|
|
|
@retval EFI_SUCCESS destroy success
|
|
**/
|
|
VOID
|
|
DestroyCursor (
|
|
IN OUT PRIVATE_MOUSE_DATA *Private
|
|
)
|
|
{
|
|
DestroyImage (&Private->Cursor);
|
|
}
|
|
|
|
/**
|
|
Move the cursor to a particular point indicated by the X, Y axis.
|
|
|
|
@param [in] X indicates location to move to.
|
|
@param [in] Y indicates location to move to.
|
|
|
|
@retval None
|
|
|
|
**/
|
|
EFI_STATUS
|
|
EFIAPI
|
|
InternalSetCursorPos (
|
|
IN UINTN X,
|
|
IN UINTN Y
|
|
)
|
|
{
|
|
PRIVATE_MOUSE_DATA *Private;
|
|
|
|
Private = mPrivate;
|
|
|
|
ASSERT_LOCKED (&Private->SetupMouseLock);
|
|
if (X < Private->MouseRange.StartX || Y < Private->MouseRange.StartY ||
|
|
X > Private->MouseRange.EndX || Y > Private->MouseRange.EndY) {
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
Private->SaveCursorX = (UINT32)X;
|
|
Private->SaveCursorY = (UINT32)Y;
|
|
if ((INT32)X != Private->Cursor.ImageRc.left || (INT32)Y != Private->Cursor.ImageRc.top) {
|
|
MoveImage (&Private->Cursor, X, Y);
|
|
}
|
|
|
|
return EFI_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
According mouse / touch event to determinate cursor postion and button state
|
|
|
|
@param [in] Event and Context Not actually used in the function
|
|
@param [in] Context
|
|
|
|
@retval EFI_SUCCESS If receive mouse / touch event
|
|
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ProcessMouse (
|
|
IN EFI_EVENT Event,
|
|
IN VOID *Context
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
PRIVATE_MOUSE_DATA *Private;
|
|
INTN CurX, CurY;
|
|
UINTN Count;
|
|
POINTER_PROTOCOL_INFO *PointerProtocolInfo;
|
|
EFI_SIMPLE_POINTER_STATE SimplePointerState;
|
|
EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointer;
|
|
EFI_ABSOLUTE_POINTER_STATE AbsolutePointerState;
|
|
UINT64 ScreenFactor;
|
|
EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerPtr;
|
|
STATIC UINTN TimeCount = 0;
|
|
BOOLEAN ImageIsSame;
|
|
RECT InvalidateRc;
|
|
RECT Rc;
|
|
GOP_ENTRY *GopEntry;
|
|
EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
|
|
LIST_ENTRY *Node;
|
|
UINTN BufferIn;
|
|
|
|
Private = SETUP_MOUSE_DEV_FROM_THIS (Context);
|
|
|
|
ASSERT (Private->IsStart);
|
|
|
|
CurX = (INTN)Private->Cursor.ImageRc.left;
|
|
CurY = (INTN)Private->Cursor.ImageRc.top;
|
|
|
|
if (IsListEmpty (&Private->GopList)) {
|
|
return ;
|
|
}
|
|
|
|
GopEntry = GOP_ENTRY_FROM_THIS (GetFirstNode (&Private->GopList));
|
|
GraphicsOutput = GopEntry->GraphicsOutput;
|
|
|
|
PointerProtocolInfo = Private->PointerProtocolInfo;
|
|
for (Count = 0; Count < PointerProtocolInfo->Count; Count ++) {
|
|
if ((PointerProtocolInfo->Data[Count].Attributes & ATTRIBUTE_BIT_SIMPLE_OR_ABSOLUTE) == ATTRIBUTE_VALUE_SIMPLE) {
|
|
//
|
|
// Use Simple Pointer protocol to update current mouse state
|
|
//
|
|
SimplePointerPtr = (EFI_SIMPLE_POINTER_PROTOCOL*) PointerProtocolInfo->Data[Count].PointerProtocol;
|
|
Status = SimplePointerPtr->GetState(SimplePointerPtr, &SimplePointerState);
|
|
if (EFI_ERROR(Status)) {
|
|
continue;
|
|
}
|
|
if (!Private->HideCursor) {
|
|
AcquireSetupMouseLock (Private);
|
|
ShowImage (&Private->Cursor);
|
|
ReleaseSetupMouseLock (Private);
|
|
}
|
|
|
|
CurX += (SimplePointerState.RelativeMovementX) / MOUSE_RESOLUTION;
|
|
CurY += (SimplePointerState.RelativeMovementY) / MOUSE_RESOLUTION;
|
|
Private->LButton = SimplePointerState.LeftButton;
|
|
Private->RButton = SimplePointerState.RightButton;
|
|
} else if ((PointerProtocolInfo->Data[Count].Attributes & ATTRIBUTE_BIT_SIMPLE_OR_ABSOLUTE) == ATTRIBUTE_VALUE_ABSOLUTE) {
|
|
//
|
|
// Use Absolute Pointer protocol to update current mouse state
|
|
//
|
|
AbsolutePointer = (EFI_ABSOLUTE_POINTER_PROTOCOL*) PointerProtocolInfo->Data[Count].PointerProtocol;
|
|
Status = AbsolutePointer->GetState (AbsolutePointer, &AbsolutePointerState);
|
|
if (EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
if (Private->HideCursorWhenTouch) {
|
|
AcquireSetupMouseLock (Private);
|
|
HideImage (&Private->Cursor);
|
|
ReleaseSetupMouseLock (Private);
|
|
}
|
|
|
|
ScreenFactor = DivU64x32 (LShiftU64 ((UINT64)(GraphicsOutput->Mode->Info->HorizontalResolution), 32), (UINT32)(AbsolutePointer->Mode->AbsoluteMaxX - AbsolutePointer->Mode->AbsoluteMinX));
|
|
CurX = (UINTN)(RShiftU64 (MultU64x32 (ScreenFactor, (UINT32)(AbsolutePointerState.CurrentX - AbsolutePointer->Mode->AbsoluteMinX)), 32));
|
|
ScreenFactor = DivU64x32 (LShiftU64 ((UINT64)(GraphicsOutput->Mode->Info->VerticalResolution), 32), (UINT32)(AbsolutePointer->Mode->AbsoluteMaxY - AbsolutePointer->Mode->AbsoluteMinY));
|
|
CurY = (UINTN)(RShiftU64 (MultU64x32 (ScreenFactor, (UINT32)(AbsolutePointerState.CurrentY - AbsolutePointer->Mode->AbsoluteMinY)), 32));
|
|
|
|
Private->LButton = (BOOLEAN) ((AbsolutePointerState.ActiveButtons & EFI_ABSP_TouchActive) == EFI_ABSP_TouchActive);
|
|
Private->RButton = (BOOLEAN) ((AbsolutePointerState.ActiveButtons & EFI_ABS_AltActive) == EFI_ABS_AltActive);
|
|
}
|
|
|
|
//
|
|
// Bugbug: if event is touch, do we fix the position ?
|
|
//
|
|
if (CurX <= (INTN) Private->MouseRange.StartX) {
|
|
CurX = (INTN) Private->MouseRange.StartX;
|
|
} else if (CurX >= (INTN) Private->MouseRange.EndX) {
|
|
CurX = (INTN) Private->MouseRange.EndX;
|
|
}
|
|
|
|
if (CurY <= (INTN) Private->MouseRange.StartY) {
|
|
CurY = (INTN) Private->MouseRange.StartY;
|
|
} else if (CurY >= (INTN) mPrivate->MouseRange.EndY) {
|
|
CurY = (INTN) Private->MouseRange.EndY;
|
|
}
|
|
|
|
SetCursorPos (CurX, CurY);
|
|
AcquireSetupMouseLock (Private);
|
|
Status = ProcessKeyboard ();
|
|
ReleaseSetupMouseLock (Private);
|
|
if (!EFI_ERROR (Status)) {
|
|
continue;
|
|
}
|
|
|
|
Private->HaveRawData = TRUE;
|
|
Private->State[Private->BufferIn].CurrentX = (UINTN) Private->Cursor.ImageRc.left;
|
|
Private->State[Private->BufferIn].CurrentY = (UINTN) Private->Cursor.ImageRc.top;
|
|
Private->State[Private->BufferIn].CurrentZ = 0;
|
|
|
|
if (Private->LButton != Private->State[Private->BufferIn].LButton ||
|
|
Private->RButton != Private->State[Private->BufferIn].RButton) {
|
|
Private->State[Private->BufferIn].LButton = Private->LButton;
|
|
Private->State[Private->BufferIn].RButton = Private->RButton;
|
|
BufferIn = Private->BufferIn + 1;
|
|
if (BufferIn == STATE_BUFFER_SIZE) BufferIn = 0;
|
|
if (BufferIn != Private->BufferOut) {
|
|
CopyMem (
|
|
&Private->State[BufferIn],
|
|
&Private->State[Private->BufferIn],
|
|
sizeof (SETUP_MOUSE_STATE)
|
|
);
|
|
Private->BufferIn = BufferIn;
|
|
}
|
|
}
|
|
}
|
|
|
|
AcquireSetupMouseLock (Private);
|
|
|
|
|
|
RenderImageForAllGop (Private);
|
|
|
|
//
|
|
// sync the keyboard state
|
|
//
|
|
UpdateKeyboardStateByBDA ();
|
|
|
|
if (!Private->NeedSyncFrameBuffer) {
|
|
ReleaseSetupMouseLock (Private);
|
|
return ;
|
|
}
|
|
|
|
//
|
|
// check screen per 30 ms
|
|
//
|
|
if (TimeCount++ < ((TICKS_PER_SECOND / 30) / MOUSE_TIMER)) {
|
|
ReleaseSetupMouseLock (Private);
|
|
return;
|
|
}
|
|
TimeCount = 0;
|
|
|
|
ImageIsSame = FALSE;
|
|
|
|
Node = GetFirstNode (&Private->GopList);
|
|
while (!IsNull (&Private->GopList, Node)) {
|
|
|
|
GopEntry = GOP_ENTRY_FROM_THIS (Node);
|
|
|
|
//
|
|
// sync (0,0) pixel with screen buffer for bitlocker
|
|
//
|
|
SetRect(&Rc, 0, 0, 1, 1);
|
|
IntersectRect (&InvalidateRc, &Rc, &GopEntry->Screen.ImageRc);
|
|
SyncScreenImage (Private, GopEntry, &InvalidateRc, &ImageIsSame);
|
|
|
|
//
|
|
// sync cursor pixel, for bitlocker read input box
|
|
//
|
|
IntersectRect (&InvalidateRc, &Private->Cursor.ImageRc, &GopEntry->Screen.ImageRc);
|
|
SyncScreenImage (Private, GopEntry, &InvalidateRc, &ImageIsSame);
|
|
if (!ImageIsSame) {
|
|
UnionRect (&GopEntry->InvalidateRc, &GopEntry->InvalidateRc, &Private->Cursor.ImageRc);
|
|
}
|
|
|
|
if (Private->Keyboard.Visible) {
|
|
IntersectRect (&InvalidateRc, &Private->Keyboard.ImageRc, &GopEntry->Screen.ImageRc);
|
|
SyncScreenImage (Private, GopEntry, &InvalidateRc, &ImageIsSame);
|
|
if (!ImageIsSame) {
|
|
UnionRect (&GopEntry->InvalidateRc, &GopEntry->InvalidateRc, &Private->Keyboard.ImageRc);
|
|
}
|
|
}
|
|
|
|
RenderImage (Private, GopEntry, TRUE);
|
|
|
|
Node = GetNextNode (&Private->GopList, Node);
|
|
}
|
|
|
|
ReleaseSetupMouseLock (Private);
|
|
}
|
|
|