diff -r 000000000000 -r 5d03bc08d59c windowing/windowserver/nga/SERVER/POINTER.CPP --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/windowing/windowserver/nga/SERVER/POINTER.CPP Tue Feb 02 01:47:50 2010 +0200 @@ -0,0 +1,1704 @@ +// Copyright (c) 1995-2009 Nokia Corporation and/or its subsidiary(-ies). +// All rights reserved. +// This component and the accompanying materials are made available +// under the terms of "Eclipse Public License v1.0" +// which accompanies this distribution, and is available +// at the URL "http://www.eclipse.org/legal/epl-v10.html". +// +// Initial Contributors: +// Nokia Corporation - initial contribution. +// +// Contributors: +// +// Description: +// Pointer functions +// +// + +#include +#include +#include "W32CLICK.H" +#include "pointer.h" +#include "rootwin.h" +#include "windowgroup.h" +#include "KEYCLICK.H" +#include "ScrDev.H" +#include "EVENT.H" +#include "panics.h" +#include "wstop.h" +#include "inifile.h" +#include +#include "advancedpointereventhelper.h" +#include "graphics/pointereventdata.h" + +TTimeIntervalMicroSeconds32 TWsPointer::iDoubleClickMaxInterval; +TInt TWsPointer::iDoubleClickMaxDistance; +CWsPointerCursor* TWsPointer::iCursorSprite; +TPointerCursorMode TWsPointer::iPointerCursorMode=EPointerCursorNormal; +TXYInputType TWsPointer::iXyInputType; +TBool TWsPointer::iTimerQueued; +TBool TWsPointer::iUpdateRequired; +CPeriodic* TWsPointer::iPeriodicTimer; +CWsRootWindow* TWsPointer::iRootWindow; +TInt TWsPointer::iMaxPointers; +TBool TWsPointer::iIs3DPointer; +RArray TWsPointer::iPointers; +TInt TWsPointer::iPrimaryPointer = TAdvancedPointerEvent::EDefaultPointerNumber; +TInt TWsPointer::iPreviousPrimaryPointer; +TInt TWsPointer::iEnterCloseProximityThreshold; +TInt TWsPointer::iExitCloseProximityThreshold; +TInt TWsPointer::iEnterHighPressureThreshold; +TInt TWsPointer::iExitHighPressureThreshold; +TBool CWsPointerBuffer::iSignalled=EFalse; +CWsPointerBuffer* CWsPointerBuffer::iCurrentBuffer=NULL; +CCirBuf* CWsPointerBuffer::iPointerBuffer=NULL; +TSglQue CWsPointerBuffer::iList(_FOFF(CWsPointerBuffer,iQue)); +TInt TWsPointer::iYOffset; + +static _LIT_SECURITY_POLICY_C1(KSecurityPolicy_SwEvent,ECapabilitySwEvent); + +void TWsPointer::InitStaticsL() + { + //This iYOffset setting is specific for capacitive touch screens, where user's finger is the pointer device. + //This is typically used so that the pointer event location is more inline with where the user perceives their + //finger to be on the screen (for example, due to refraction and the relatively large touch area of a finger). + iYOffset = 0; + _LIT( KWSERVIniFileVarYShifting, "YSHIFTING"); + TBool fetchingSucceeded = WsIniFile->FindVar(KWSERVIniFileVarYShifting, iYOffset); + WS_ASSERT_ALWAYS(iYOffset>=0, EWsPanicInvalidPointerOffset); + if ( !fetchingSucceeded ) + { + iYOffset = 0; + } + + iRootWindow = CWsTop::Screen()->RootWindow(); + + TMachineInfoV1Buf machineInfo; + UserHal::MachineInfo(machineInfo); + iXyInputType=machineInfo().iXYInputType; + + // Read EPointerMaxPointers from HAL and check if reported value is consistent + // with iXyInputType. + // Even if HAL reports that device doesn't support any pointer, WSERV + // always has to support at least one pointer for compatibility reasons + // and for keeping state of pointer cursor. + if(HAL::Get(HALData::EPointerMaxPointers,iMaxPointers)!=KErrNone) + { + iMaxPointers = 1; + } + else + { + WS_ASSERT_ALWAYS(iMaxPointers >= 0 && iMaxPointers <= TAdvancedPointerEvent::EMaximumWServNumberOfPointers, + EWsPanicMaxPointersOutOfRange); + WS_ASSERT_ALWAYS(( XyInput() && iMaxPointers > 0) || (!XyInput() && iMaxPointers == 0), + EWsPanicMaxPointersInconsistent); + if (iMaxPointers == 0) + { + iMaxPointers = 1; + } + } + + // Does device support Z coordinate of the pointers? + if(HAL::Get(HALData::EPointer3D,iIs3DPointer)!=KErrNone) + { + iIs3DPointer=EFalse; // No API, then no 3D pointers + } + WS_ASSERT_ALWAYS(!iIs3DPointer || XyInput(), EWsPanicPointer3DInconsistent); + + // Initialize thresholds for EEnterCloseProximity, EExitCloseProximity, + // EEnterHighPressure and EExitHightPressure events. + if(HAL::Get(HALData::EPointer3DEnterCloseProximityThreshold, + iEnterCloseProximityThreshold) != KErrNone) + { + iEnterCloseProximityThreshold = KMaxTInt; + } + if(HAL::Get(HALData::EPointer3DExitCloseProximityThreshold, + iExitCloseProximityThreshold) != KErrNone) + { + iExitCloseProximityThreshold = KMinTInt; + } + if(HAL::Get(HALData::EPointer3DEnterHighPressureThreshold, + iEnterHighPressureThreshold) != KErrNone) + { + iEnterHighPressureThreshold = KMaxTInt; + } + if(HAL::Get(HALData::EPointer3DExitHighPressureThreshold, + iExitHighPressureThreshold) != KErrNone) + { + iExitHighPressureThreshold = KMinTInt; + } + + iPointers = RArray(iMaxPointers); + TWsPointer emptyPointer; + emptyPointer.iRepeatTimer = NULL; + emptyPointer.Clear(); + for (TInt ii = 0; ii < iMaxPointers; ii++) + { + emptyPointer.iNumber = ii; + User::LeaveIfError(iPointers.Append(emptyPointer)); + RepeatTimer(ii) = CWsPointerTimer::NewL(iPointers[ii]); + } + + iPeriodicTimer=CPeriodic::NewL(EPointerCursorPriority); + } + +void TWsPointer::Clear() + { + iState = EPointerStateOutOfRange; + iPos.iX = 0; + iPos.iY = 0; + iPressureProximity = 0; + iCurrentWindow=MovesAvailable() ? iRootWindow : NULL; + iActualWinPointerIsOver = NULL; + iGrabWindow = NULL; + iLastUnmatchedDown1 = NULL; + iLastUnmatchedDown2 = NULL; + iLastUnmatchedDown3 = NULL; + iLastUnmatchedEnterHighPressure = NULL; + iPrevClickWindow = NULL; + iInCloseProximity = EFalse; + iInHighPressure = EFalse; + CancelPointerRepeatEventRequest(); + } + +/** +Turns off pointer cursor, deletes permenently pointer cursor update timer and pointer event repeat timer. +*/ +void TWsPointer::Stop() + { + SetPointerCursorMode(EPointerCursorNone); + UpdatePointerCursor(); + delete iPeriodicTimer; + } + +void TWsPointer::DeleteStatics() + { + for (TInt ii = 0; ii < iMaxPointers; ii++) + { + delete RepeatTimer(ii); + } + iPointers.Close(); + } + +void TWsPointer::SetPointerCursorPos(TPoint aPos) + { + RestrictPos(aPos,EFalse); + iPointers[iPrimaryPointer].iPos=aPos; + iPointers[iPrimaryPointer].ReLogCurrentWindow(); + UpdatePointerCursor(); + } + +void TWsPointer::SendEnterExitEvent(TEventCode aType) + { + if (iCurrentWindow + && (iState != EPointerStateOutOfRange) + && (iNumber == iPrimaryPointer || iCurrentWindow->AdvancedPointersEnabled()) + && !(iCurrentWindow->PointerFilter()&EPointerFilterEnterExit) + && !iCurrentWindow->ShutDownInProgress()) + { + iCurrentWindow->QueueEvent(aType, iNumber); + } + } + +void TWsPointer::SetCurrentWindow(const CWsWindow* aWin) + { + if (aWin!=iCurrentWindow) + { + SendEnterExitEvent(EEventPointerExit); + iCurrentWindow=aWin; + SendEnterExitEvent(EEventPointerEnter); + } + } + +/** +Relogs the current window (sets iCurrentWindow) for this pointer. +Retrieves pointer relative position in current window and pointer position in current +window's parent window. +*/ +void TWsPointer::ReLogCurrentWindow(TPoint &aPos, TPoint &aParentPos, const CWsWindowGroup* aForceInGroup) + { + if (iRootWindow) + { + SetCurrentWindow(iRootWindow->PointerWindow(iPos,&aPos,&aParentPos,iGrabWindow, + iActualWinPointerIsOver,aForceInGroup)); + } + else + { + iCurrentWindow=NULL; + } + } + +/** +Relog all pointer's current windows when the window layout has changed. +*/ +void TWsPointer::ReLogPointersCurrentWindows() + { + for (TInt ii = 0; ii < iMaxPointers; ii++) + { + TWsPointer& pointer = iPointers[ii]; + pointer.ReLogCurrentWindow(); + } + } + +/* +Relog this pointer's current pointer window when the window layout has changed. +Works similarly to ReLogCurrentWindow(TPoint &aPos, TPoint &aParentPos, const CWsWindowGroup* aForceInGroup), +but doesn't set relative positions. +*/ +void TWsPointer::ReLogCurrentWindow() + { + if (iCurrentWindow) + { + SetCurrentWindow(iRootWindow->PointerWindow(iPos,NULL,NULL,iGrabWindow,iActualWinPointerIsOver,NULL)); + } + } + +/* +Called when a window has changed it's filter state, will trigger a 'Enter' message if the window +is the current window +*/ +void TWsPointer::ReLogWindow(const CWsWindow* aWin) + { + for (TInt ii = 0; ii < iMaxPointers; ii++) + { + if (aWin == iPointers[ii].iCurrentWindow) + { + iPointers[ii].SendEnterExitEvent(EEventPointerEnter); + } + } + } + +void TWsPointer::UnmatchedEventPurged(TPointerEvent::TType aPointerType, TUint aHandle) + { + if (aPointerType==TPointerEvent::EButton1Up) + { + if (iGrabWindow && iGrabWindow->ClientHandle()==aHandle) + { + iGrabWindow=NULL; + } + if (iRepeatWindow && iRepeatWindow->ClientHandle()==aHandle) + { + CancelPointerRepeatEventRequest(); + } + } + switch(aPointerType) + { + case TPointerEvent::EButton1Up: + iLastUnmatchedDown1=aHandle; + break; + case TPointerEvent::EButton2Up: + iLastUnmatchedDown2=aHandle; + break; + case TPointerEvent::EButton3Up: + iLastUnmatchedDown3=aHandle; + break; + case TPointerEvent::EExitHighPressure: + iLastUnmatchedEnterHighPressure=aHandle; + break; + default:; + } + } + +void TWsPointer::WindowDisconnected(const CWsWindow* deletedWindow) + { + for (TInt pointerNum = 0; pointerNum < iMaxPointers; pointerNum++) + { + TWsPointer& pointer = iPointers[pointerNum]; + if (pointer.iRepeatWindow==deletedWindow) + { + pointer.CancelPointerRepeatEventRequest(); + } + if (pointer.iGrabWindow==deletedWindow) + { + pointer.iGrabWindow=NULL; + } + if (pointer.iCurrentWindow==deletedWindow) + { + pointer.ReLogCurrentWindow(); + if (pointerNum == iPrimaryPointer) + { + UpdatePointerCursor(); + } + } + } + } + +/* +Callback function pointer for up event remove event queue walk +*/ +TEventQueueWalkRet RemovePointerUpFunc(TAny* aHandle, TWsEvent* aEvent) + { + if (aEvent->Type()==EEventPointer && aEvent->Pointer()->iType==TPointerEvent::EButton1Up && (*(TUint *)aHandle)==aEvent->Handle()) + { + return(EEventQueueWalkDeleteEvent); + } + return(EEventQueueWalkOk); + } + +/* +If the specified pointer is down claim grab in aWindow as though the down event had +gone to this window. Also send an up event to the window (if any) that would receive it if the +pointer was released now. +If no pointer is specifed do the above for the primary pointer. + +@return KErrNone if successful, + KErrNotFound if pointernumber out of range, + KErrNotSupported if incorrect pointer grab claimed for window in emulation mode, + KErrPermissionDenied if trying to grab from a different window owner without the required capability. +*/ +TInt TWsPointer::ClaimGrab(const CWsWindow *aWindow,const TWsWinCmdGrabControl& aGrabControl) + { + TInt pointerNumber(aGrabControl.HasPointerNumber() ? aGrabControl.pointerNumber : iPrimaryPointer); + TBool advancedPointersEnabled(aWindow->AdvancedPointersEnabled()); + TInt errNo(KErrNone); + + if(!advancedPointersEnabled && aGrabControl.HasPointerNumber() && (TAdvancedPointerEvent::EDefaultPointerNumber!=pointerNumber)) + { + // The window is in emulation mode, and cannot get events for anything other than the primary pointer + errNo=KErrNotSupported; + } + else if(advancedPointersEnabled && ((pointerNumber<0) || (pointerNumber>=iMaxPointers))) + { + // Unknown pointer number + errNo=KErrNotFound; + } + else if(aGrabControl.HasPointerNumber() && (aWindow->WsOwner()!=iPointers[pointerNumber].iCurrentWindow->WsOwner()) + && !KSecurityPolicy_SwEvent().CheckPolicy(aWindow->WsOwner()->ClientMessage(), __PLATSEC_DIAGNOSTIC_STRING("Capability check failed for RWindowBase::ClaimPointerGrab"))) + { + // Trying to grab from a different window owner requires the relevant permission + // - Only for the multipointer API, RWindowBase::ClaimPointerGrab(TInt, TBool), which provides a pointer number + // - Doing so for the legacy non-multipointer API, RWindowBase::ClaimPointerGrab(TBool), would be a compatibility break + errNo=KErrPermissionDenied; + } + else + { + iPointers[pointerNumber].ClaimGrab(aWindow,aGrabControl.CheckFlags(TWsWinCmdGrabControl::ESendUpEvent)); + } + + return errNo; + } + +/* +If this pointer is down claim grab in aWindow as though the down event had +gone to this window. Also send an up event to the window (if any) that would receive it if the +pointer was released now. +*/ +void TWsPointer::ClaimGrab(const CWsWindow* aWindow,TBool aSendUpEvent) + { + TInt modState=TWindowServerEvent::GetModifierState(); + TWsEvent event; + TAdvancedPointerEvent& pointerEvent=*event.Pointer(); + TAdvancedPointerEventHelper::InitAdvancedPointerEvent(event, TPointerEvent::EButton1Up,modState,TPoint3D(iPos.iX,iPos.iY,iPressureProximity),iNumber); + if (iState == EPointerStateDown) + { + if (iCurrentWindow!=aWindow) + { + if (aSendUpEvent) + { + ProcessEvent(event,NULL,EFalse); + } + else // If up event already in queue purge it + { + CEventQueue* eventQueue = iCurrentWindow->EventQueue(); + if (eventQueue) + { + TUint handle=iCurrentWindow->ClientHandle(); + eventQueue->WalkEventQueue(&RemovePointerUpFunc,&handle); + } + } + iState = EPointerStateDown; + if (aWindow->HasPointerGrab()) + { + iGrabWindow=aWindow; + } + ReLogCurrentWindow(pointerEvent.iPosition,pointerEvent.iParentPosition,NULL); + pointerEvent.iType=TPointerEvent::EDrag; + ProcessPointerEvent(event); + } + } + else if (iState == EPointerStateUp) + { + const CWsWindow *current=iCurrentWindow; + iCurrentWindow=aWindow; + WS_ASSERT_DEBUG(iGrabWindow==NULL, EWsPanicPointerClaimGrab); + iGrabWindow=aWindow; // Force the up event to be sent to aWindow + ReLogCurrentWindow(pointerEvent.iPosition,pointerEvent.iParentPosition,NULL); + ProcessPointerEvent(event); + iGrabWindow=NULL; + iCurrentWindow=current; + } + } + +/** +@return ETrue if matching event has been purged, so current event should not be delivered, + EFalse otherwise. +*/ +TBool TWsPointer::CheckMatchingEventPurged(TPointerEvent::TType aType) + { + switch(aType) + { + TUint lastUnmatchedDown; + case TPointerEvent::EButton1Up: + lastUnmatchedDown=iLastUnmatchedDown1; + iLastUnmatchedDown1=0; + iLastUnmatchedEnterHighPressure=0; + goto lastUnmatchedDownCheck; + case TPointerEvent::EButton2Up: + lastUnmatchedDown=iLastUnmatchedDown2; + iLastUnmatchedDown2=0; + goto lastUnmatchedDownCheck; + case TPointerEvent::EButton3Up: + lastUnmatchedDown=iLastUnmatchedDown3; + iLastUnmatchedDown3=0; + goto lastUnmatchedDownCheck; + case TPointerEvent::EExitHighPressure: + lastUnmatchedDown=iLastUnmatchedEnterHighPressure; + iLastUnmatchedEnterHighPressure=0; +lastUnmatchedDownCheck: + if (lastUnmatchedDown==iCurrentWindow->ClientHandle()) + { + return ETrue; // Don't deliver the event as we've already thrown away matching event + } + default: //Should never get to default + break; + } + return EFalse; + } + +TBool TWsPointer::QueuePointerEvent(const CWsWindow* aWindow, TWsEvent &aEvent) + { + if (aWindow->WsOwner() && + (aWindow->AdvancedPointersEnabled() || + TAdvancedPointerEventHelper::PointerNumber(aEvent) == iPrimaryPointer)) + { + CEventQueue* queue=aWindow->EventQueue(); + aEvent.SetHandle(aWindow->ClientHandle()); + if (aEvent.Handle()!=0) + { + if(!aWindow->AdvancedPointersEnabled()) + { + // Re-assign from WServ primary pointer number, to EDefaultPointerNumber for Cone and other clients. + // This should not get confused with any real pointer of the same number due to the TWsEvents' window handle + // being different. + TAdvancedPointerEventHelper::SetPointerNumber(aEvent,TAdvancedPointerEvent::EDefaultPointerNumber); + aEvent.Pointer()->iModifiers&=~EModifierAdvancedPointerEvent; // Clear the advanced pointer flag + } + if (queue->UpdateLastPointerEvent(aEvent)) + { + return EFalse; + } + TWservEventPriorities priority=EEventPriorityLow; + switch (aEvent.Pointer()->iType) + { + case TPointerEvent::EButton1Up: + case TPointerEvent::EButton2Up: + case TPointerEvent::EButton3Up: + case TPointerEvent::EExitHighPressure: + if (CheckMatchingEventPurged(aEvent.Pointer()->iType)) + { + return ETrue; + } + if (queue->CheckRoom()) + { + if (CheckMatchingEventPurged(aEvent.Pointer()->iType)) + { + return ETrue; + } + } + /*Fall Through if an event was not purged*/ + case TPointerEvent::EButton1Down: + case TPointerEvent::EButton2Down: + case TPointerEvent::EButton3Down: + case TPointerEvent::EEnterHighPressure: + case TPointerEvent::EOutOfRange: + priority=EEventPriorityHigh; + break; + default:; + } + queue->QueueEvent(aEvent,priority); + } + } + return EFalse; + } + +/* +Moves the window group which contains this pointer's iCurrentWindow on top. +*/ +void TWsPointer::ProcessForegroundCheck() + { + CWsWindowGroup* group=((CWsTopClientWindow *)iCurrentWindow)->TopClientWindow()->Parent(); + if (group->iFlags&CWsWindowGroup::EGroupFlagAutoForeground) + { + group->SetOrdinalPosition(0); + } + } + +/* +Pointer Event Processing - stage 3 of 3: +- setting event's time +- auto foreground check +- double clicks detection +- pointer repeats +- add event to client's queue +- drag&drop capturing +*/ +void TWsPointer::ProcessPointerEvent(TWsEvent& aEvent) + { + if (iCurrentWindow && iCurrentWindow!=iRootWindow) + { + aEvent.SetType(EEventPointer); + aEvent.SetTimeNow(); + TPointerEvent::TType type=aEvent.Pointer()->iType; + switch(type) + { + //TUint lastUnmatchedDown; + case TPointerEvent::EButton1Down: + ProcessForegroundCheck(); + /*Fall Through*/ + case TPointerEvent::EButton2Down: + case TPointerEvent::EButton3Down: + { + TPoint& pos=aEvent.Pointer()->iPosition; + if (iCurrentWindow==iPrevClickWindow && + type==iPrevClickEventType && + (Abs(pos.iX-iPrevClickPos.iX)+Abs(pos.iY-iPrevClickPos.iY))iModifiers|=EModifierDoubleClick; + iPrevClickWindow=NULL; // Set to NULL to block a double double click + } + else + { + iPrevClickWindow=iCurrentWindow; + } + iPrevClickEventType=type; + iPrevClickPos=pos; + iPrevClickTime=aEvent.Time(); + } + break; + default: + break; + } + if (iRepeatWindow) + { + if (PointerEventRepeatCheck(&aEvent, iCurrentWindow->ClientHandle())) + { + return; + } + CancelPointerRepeatEventRequest(); + } + if (QueuePointerEvent(iCurrentWindow, aEvent)) + { + return; + } + if (iCurrentWindow->DragDropCapture()) + { + aEvent.SetType(EEventDragDrop); + QueuePointerEvent(iActualWinPointerIsOver, aEvent); + } + } + } + +TInt PointerTimerCallBack(TAny *) + { + TWsPointer::TimerExpired(); + return(KErrNone); + } + +void TWsPointer::RestrictPos(TPoint& aPos,TBool aWithinDrawableArea/*=ETrue*/) + { + CScreen* screen = iRootWindow->Screen(); + WS_ASSERT_DEBUG(screen->IsValidScreenSizeMode(screen->ScreenSizeMode()), EWsPanicInvalidScreenSizeMode); +#if defined(__WINS__) + if (aWithinDrawableArea) + { + if (!DeltaMouse() && !TRect(screen->DrawableArea()).Contains(aPos)) + { + return; //Not in the drawable area so user may be trying to click on facia button. + } + } +#endif + TRect validRect=screen->GetPointerCursorArea(screen->ScreenSizeMode()); + if (aPos.iX=validRect.iBr.iX) + aPos.iX=validRect.iBr.iX-1; + if (aPos.iY=validRect.iBr.iY) + aPos.iY=validRect.iBr.iY-1; + } + +#if defined(__WINS__) +TBool TWsPointer::PreProcessDriverEvent(TRawEvent &aRawEvent,TBool aFromHardware/*=EFlase*/) +#else +TBool TWsPointer::PreProcessDriverEvent(TRawEvent &aRawEvent) +#endif + { + TRawEvent::TType type=aRawEvent.Type(); + + if (!IsPointerEventType(type)) + return ETrue; + + if (!XyInput()) + { + return EFalse; + } + + // check correctness of aRawEvent.PointerNumber() + if (iMaxPointers > 1) + { + if (aRawEvent.PointerNumber() >= iMaxPointers) + { + return EFalse; + } + } + else + { + aRawEvent.SetPointerNumber(0); + } + + if (type != TRawEvent::EPointer3DOutOfRange) + { + // operations on coordinates are valid for all types except EPointer3DOutOfRange + TPoint xy=aRawEvent.Pos(); + if (DeltaMouse()) + { + #if defined(__WINS__) + if (aFromHardware) + return EFalse; + #endif + if (type==TRawEvent::EPointerMove) + { + xy+=iPointers[aRawEvent.PointerNumber()].iPos; + ShiftYCoordinate(xy.iY); + RestrictPos(xy); + } + else + xy=iPointers[aRawEvent.PointerNumber()].iPos; + } + else + { + CScreen* screen=iRootWindow->Screen(); + #if !defined(__WINS__) + TSize screenSize=screen->SizeInPixels()-TSize(1,1); //This is in the current rotation + switch (screen->Orientation()) + { + case CFbsBitGc::EGraphicsOrientationRotated90: + xy.SetXY(xy.iY,screenSize.iHeight-xy.iX); + break; + case CFbsBitGc::EGraphicsOrientationRotated180: + xy=-(xy-screenSize); + break; + case CFbsBitGc::EGraphicsOrientationRotated270: + xy.SetXY(screenSize.iWidth-xy.iY,xy.iX); + break; + default:; //To stop warning + } + #endif + ShiftYCoordinate(xy.iY); + // Move the raw event position by shifting it by Origin and scale + xy=screen->PhysicalToLogical(xy); + RestrictPos(xy); + } + aRawEvent.Set(type, xy.iX, xy.iY, + iIs3DPointer ? aRawEvent.Pos3D().iZ : 0); + } + return ETrue; + } + +/** + * Validates events sent to the Window Server by its Client (Anim or Window Group). + * May overwrite aRawEvent's Z coordinate and/or pointer number if Client or digitizer driver + * doesn't support them. + * @param aRawEvent event to validate + * @param aAdvancedPointersEnabled ETrue if Client supports advanced pointer's data (Z coordiante + * and pointer number); EFalse otherwise. + * @return ETrue if aRawEvent should be processed by Window Server. EFalse if it should be ignored. + */ +TBool TWsPointer::PreProcessClientEvent(TRawEvent &aRawEvent, TBool aAdvancedPointersEnabled) + { + TRawEvent::TType type=aRawEvent.Type(); + + if (!IsPointerEventType(type)) + return ETrue; + + // validate pointer number + if (aAdvancedPointersEnabled) + { + // ignore event if both digitizer driver and Client support pointer numbers, but number is invalid + if (aRawEvent.PointerNumber() >= iMaxPointers) + { + return EFalse; + } + } + else + { + // set to iPrimaryPointer if Client doesn't support pointer numbers + aRawEvent.SetPointerNumber(iPrimaryPointer); + } + + // validate Z coordinate for all pointer events except EPointer3DOutOfRange + if (type != TRawEvent::EPointer3DOutOfRange) + { + if (!iIs3DPointer) + { + // set Z to 0 for all events when the digitizer driver doesn't support Z coordinate + TPoint3D xyz=aRawEvent.Pos3D(); + aRawEvent.Set(type, xyz.iX, xyz.iY, 0); + } + else if (!aAdvancedPointersEnabled) + { + // set Z to actual value if the digitizer driver does support Z coordinate but Client doesn't + TPoint3D xyz=aRawEvent.Pos3D(); + aRawEvent.Set(type, xyz.iX, xyz.iY, iPointers[aRawEvent.PointerNumber()].iPressureProximity); + } + } + + return ETrue; + } + +TBool TWsPointer::IsPointerEventType(TRawEvent::TType aType) + { +#if defined(__WINS__) + WS_ASSERT_DEBUG(TRawEvent::EPointerMove==1, EWsPanicRawEventsTypeChanged); + WS_ASSERT_DEBUG(TRawEvent::EPointerMove+1==TRawEvent::EPointerSwitchOn, EWsPanicRawEventsTypeChanged); + WS_ASSERT_DEBUG(TRawEvent::EPointerSwitchOn+8==TRawEvent::EButton1Down, EWsPanicRawEventsTypeChanged); + WS_ASSERT_DEBUG(TRawEvent::EButton1Down+5==TRawEvent::EButton3Up, EWsPanicRawEventsTypeChanged); + WS_ASSERT_DEBUG(TRawEvent::EButton3Up+6==TRawEvent::EPointer3DOutOfRange, EWsPanicRawEventsTypeChanged); +#endif + return (aType == TRawEvent::EPointerMove) || + (aType == TRawEvent::EPointerSwitchOn) || + (aType >= TRawEvent::EButton1Down && aType <= TRawEvent::EButton3Up) || + (aType == TRawEvent::EPointer3DOutOfRange); + } + +/* +Pointer Event processing. + +This method redirects pointer event processing to proper TWsPointer object. +*/ +void TWsPointer::ProcessWsEvent(TWsEvent& aEvent,const CWsWindowGroup* aForceInGroup,TBool aNatural) + { + if(iPrimaryPointer!=iPreviousPrimaryPointer) + { + // The primary pointer may be updated while the TRawEvent is being processed, but this TRawEvent may be + // then be consumed by an anim. + // If it hasn't then we can leave any repeat request. + CancelPointerRepeatEventRequest(iPreviousPrimaryPointer); + } + + if (aEvent.Pointer()->iType == TPointerEvent::EOutOfRange) + { + iPointers[TAdvancedPointerEventHelper::PointerNumber(aEvent)].ProcessOutOfRangeEvent(aEvent, aForceInGroup, aNatural); + } + else + { + iPointers[TAdvancedPointerEventHelper::PointerNumber(aEvent)].ProcessEvent(aEvent, aForceInGroup, aNatural); + } + } + +/* +Pointer Event Processing - stage 1 of 3: +- updating this pointer's state: coordinates and grabbing window +- updating coordinates of event +- updating event type to Drag +- simulated moves +- generating events: EEnterCloseProximity, EExitCloseProximity, EEnterHighPressure, EExitHighPressure +*/ +void TWsPointer::ProcessEvent(TWsEvent& aEvent,const CWsWindowGroup* aForceInGroup,TBool aNatural) + { + TAdvancedPointerEvent& pointerEvent = *aEvent.Pointer(); + TPointerEvent::TType eventType=pointerEvent.iType; + + if (iState == EPointerStateOutOfRange) + { + // new pointer comes in range, so clear information after previous one + Clear(); + } + + // update coordinates + iPos=pointerEvent.iPosition; + iPressureProximity=TAdvancedPointerEventHelper::Z(aEvent); + + if (eventType == TPointerEvent::EMove && !MovesAvailable() && iState != EPointerStateDown) + { + return; + } + + // re-log and update parent position + TPoint parPos; + ReLogCurrentWindow(pointerEvent.iPosition,parPos,aForceInGroup); + pointerEvent.iParentPosition=parPos; + + // update state + switch(eventType) + { + case TPointerEvent::EButton1Down: + if (iGrabWindow==NULL && iCurrentWindow->HasPointerGrab()) + { + iGrabWindow=iCurrentWindow; + } + if (!MovesAvailable() && iCurrentWindow->PointerFilter()&EPointerGenerateSimulatedMove) + { + pointerEvent.iType=TPointerEvent::EMove; + ProcessEvent(aEvent, EFalse); + pointerEvent.iType=TPointerEvent::EButton1Down; + } + switch(iState) + { + case EPointerStateOutOfRange: + iState = EPointerStateDown; + SendEnterExitEvent(EEventPointerEnter); + // intentional lack of break statement + case EPointerStateUp: + iState = EPointerStateDown; + ProcessEvent(aEvent, aNatural); + if (iPressureProximity >= iEnterHighPressureThreshold) + { + iInHighPressure = ETrue; + pointerEvent.iType = TPointerEvent::EEnterHighPressure; + ProcessEvent(aEvent, EFalse); + } + else + { + iInHighPressure = EFalse; + } + break; + case EPointerStateDown: + if (iInHighPressure && iPressureProximity < iExitHighPressureThreshold) + { + iInHighPressure = EFalse; + eventType = TPointerEvent::EExitHighPressure; + } + else if (!iInHighPressure && iPressureProximity >= iEnterHighPressureThreshold) + { + iInHighPressure = ETrue; + eventType = TPointerEvent::EEnterHighPressure; + } + ProcessEvent(aEvent, aNatural); + break; + } + break; + case TPointerEvent::EButton1Up: + iGrabWindow=NULL; + switch(iState) + { + case EPointerStateDown: + iState = EPointerStateUp; + ProcessEvent(aEvent, aNatural); + if (iPressureProximity < iExitCloseProximityThreshold) + { + pointerEvent.iType = TPointerEvent::EExitCloseProximity; + iInCloseProximity = EFalse; + ProcessEvent(aEvent, EFalse); + } + else + { + iInCloseProximity = ETrue; + } + break; + case EPointerStateOutOfRange: + iState = EPointerStateUp; + SendEnterExitEvent(EEventPointerEnter); + // intentional lack of break statement + case EPointerStateUp: + if (iInCloseProximity && + iPressureProximity < iExitCloseProximityThreshold) + { + iInCloseProximity = EFalse; + pointerEvent.iType = TPointerEvent::EExitCloseProximity; + } + else if (!iInCloseProximity && + iPressureProximity >= iEnterCloseProximityThreshold) + { + iInCloseProximity = ETrue; + pointerEvent.iType = TPointerEvent::EEnterCloseProximity; + } + ProcessEvent(aEvent, aNatural); + break; + } + break; + case TPointerEvent::EMove: + switch(iState) + { + case EPointerStateDown: + if (iInHighPressure && + iPressureProximity < iExitHighPressureThreshold) + { + iInHighPressure = EFalse; + pointerEvent.iType = TPointerEvent::EExitHighPressure; + } + else if (!iInHighPressure && + iPressureProximity >= iEnterHighPressureThreshold) + { + iInHighPressure = ETrue; + pointerEvent.iType = TPointerEvent::EEnterHighPressure; + } + else + { + pointerEvent.iType = TPointerEvent::EDrag; + } + break; + case EPointerStateUp: + if (iInCloseProximity && + iPressureProximity < iExitCloseProximityThreshold) + { + iInCloseProximity = EFalse; + pointerEvent.iType = TPointerEvent::EExitCloseProximity; + } + else if (!iInCloseProximity && + iPressureProximity >= iEnterCloseProximityThreshold) + { + iInCloseProximity = ETrue; + pointerEvent.iType = TPointerEvent::EEnterCloseProximity; + } + break; + case EPointerStateOutOfRange: + iState = EPointerStateUp; + SendEnterExitEvent(EEventPointerEnter); + if (iPressureProximity >= iEnterCloseProximityThreshold) + { + iInCloseProximity = ETrue; + pointerEvent.iType = TPointerEvent::EEnterCloseProximity; + } + break; + } + ProcessEvent(aEvent, aNatural); + break; + default: + ProcessEvent(aEvent, aNatural); + break; + } + } + +/** +Processes OutOfRange events: +- injects event to key click plugin +- directs event to the last current window +- sends Exit event +*/ +void TWsPointer::ProcessOutOfRangeEvent(TWsEvent& aEvent,const CWsWindowGroup* aForceInGroup, TBool aNatural) + { + if (iState != EPointerStateOutOfRange) + { + // OutOfRange event generated by driver doesn't contain correct coordinates, + // we update them from last state in order to deliver event to the proper window. + SendEnterExitEvent(EEventPointerExit); + + iState = EPointerStateOutOfRange; + + TAdvancedPointerEventHelper::SetPointerNumber(aEvent, iNumber); + TAdvancedPointerEventHelper::SetZ(aEvent, iPressureProximity); + + TAdvancedPointerEvent& pointerEvent = *aEvent.Pointer(); + iCurrentWindow=iRootWindow->PointerWindow(iPos,&pointerEvent.iPosition,&pointerEvent.iParentPosition,iGrabWindow, + iActualWinPointerIsOver,aForceInGroup); + ProcessEvent(aEvent, aNatural); + } + } + +void TWsPointer::NotifyCClick(TAdvancedPointerEvent& aPointerEvent) + { + if (CClick::IsHandler()) + { + CClick::PointerEvent(iPos,aPointerEvent); + TPointerEventData params; + params.iVersion=0; + params.iCurrentPos=iPos; + TAdvancedPointerEventHelper::Copy(aPointerEvent, params.iPointerEvent); + params.iClientHandle=iCurrentWindow->ClientHandle(); + params.iWindowOrigin=iCurrentWindow->Origin(); + CWsWindowGroup* groupWin=iCurrentWindow->WinGroup(); + params.iWindowGroupId=groupWin ? groupWin->Identifier() : 0; + params.iSource=TPointerEventData::EUnspecified; + CClick::OtherEvent(EEventPointer,¶ms); + } + } + +/* +Pointer Event Processing - stage 2 of 3: +- injecting events to key click plugin +- pointer filtering +- injection to event buffer +- injection to keyboard emulator +- clearing iCurrentWindow if going up and !MovesAvailable() +- updating pointer cursor +*/ +void TWsPointer::ProcessEvent(TWsEvent& aEvent, TBool aNatural) + { + if (aNatural) + { + NotifyCClick(*aEvent.Pointer()); + } + + TUint filter=iCurrentWindow->PointerFilter(); + TPointerEvent::TType type=aEvent.Pointer()->iType; + if ((type!=TPointerEvent::EMove || !(filter&EPointerFilterMove)) && + (type!=TPointerEvent::EDrag || !(filter&EPointerFilterDrag))) + { + if (iNumber == iPrimaryPointer) + { + TPoint pos=aEvent.Pointer()->iPosition; + if ((type==TPointerEvent::EMove || type==TPointerEvent::EDrag) && iCurrentWindow->UsingPointerBuffer()) + { + CWsPointerBuffer::PointerEvent((CWsClientWindow *)iCurrentWindow,pos); + } + else if ((type==TPointerEvent::EEnterCloseProximity || type==TPointerEvent::EExitCloseProximity || + type==TPointerEvent::EEnterHighPressure || type==TPointerEvent::EExitHighPressure) && + iCurrentWindow->UsingPointerBuffer()) + { + CWsPointerBuffer::PointerEvent((CWsClientWindow *)iCurrentWindow,pos); + ProcessPointerEvent(aEvent); + } + else if (!WsKeyboardEmulator::PointerEvent(type,pos,iCurrentWindow->PointerKeyList())) + { + ProcessPointerEvent(aEvent); + } + } + else if (!iCurrentWindow->UsingPointerBuffer() || (type != TPointerEvent::EMove && type != TPointerEvent::EDrag)) + { + ProcessPointerEvent(aEvent); + } + } + if (!MovesAvailable() && (type==TPointerEvent::EButton1Up || + type==TPointerEvent::ESwitchOn || + type==TPointerEvent::EOutOfRange)) + { + iCurrentWindow=NULL; + } + if (iNumber == iPrimaryPointer) + { + PointerCursorUpdateCheck(); + } + } + +void TWsPointer::TimerExpired() + { + WS_ASSERT_DEBUG(iTimerQueued, EWsPanicPointerTimer); + if (iUpdateRequired) + { + UpdatePointerCursor(); + iUpdateRequired=EFalse; + } + else + { + iTimerQueued=EFalse; + iPeriodicTimer->Cancel(); + } + } + +void TWsPointer::GetDoubleClickSettings(TTimeIntervalMicroSeconds32 &aTime, TInt &aDistance) + { + aTime=iDoubleClickMaxInterval; + aDistance=iDoubleClickMaxDistance; + } + +void TWsPointer::SetDoubleClick(const TTimeIntervalMicroSeconds32 &aTime, TInt aDistance) + { + iDoubleClickMaxInterval=aTime; + iDoubleClickMaxDistance=aDistance; + } + +void TWsPointer::PointerCursorUpdateCheck() + { + CWsPointerCursor* sprite=CalculatePointerCursor(); + if (iCursorSprite || sprite) // If there either was, or is a pointer cursor we need an update + { + if (!iTimerQueued) + { + UpdatePointerCursorTo(sprite); + iPeriodicTimer->Start(TTimeIntervalMicroSeconds32(EPointerUpdateGapInMicroSeconds), + TTimeIntervalMicroSeconds32(EPointerUpdateGapInMicroSeconds), + TCallBack(PointerTimerCallBack,NULL)); + iTimerQueued=ETrue; + } + else + { + iUpdateRequired=ETrue; + } + } + } + +void TWsPointer::UpdatePointerCursor() + { +//__PROFILE_START(3); + CWsPointerCursor* sprite=iPointers[iPrimaryPointer].CalculatePointerCursor(); + UpdatePointerCursorTo(sprite); +//__PROFILE_END(3); + } + +void TWsPointer::UpdatePointerCursorTo(CWsPointerCursor* aNewCursor) + { + if (iCursorSprite!=aNewCursor) + { + if (iCursorSprite) + { + iCursorSprite->Deactivate(); + } + iCursorSprite=aNewCursor; + if (iCursorSprite) + { + iCursorSprite->SetPos(iPointers[iPrimaryPointer].iPos); + iCursorSprite->Activate(); + } + } + else if (iCursorSprite) + { + iCursorSprite->SetPos(iPointers[iPrimaryPointer].iPos); + } + } + +CWsPointerCursor* TWsPointer::CalculatePointerCursor() + { + CWsPointerCursor* sprite=NULL; + if (iCurrentWindow && (iPointerCursorMode==EPointerCursorNormal || iPointerCursorMode==EPointerCursorWindow)) + { + const CWsWindowBase* window=iCurrentWindow; + do { + sprite=window->PointerCursor(); + if (window->WinType()!=EWinTypeClient) + { + break; + } + window=window->BaseParent(); + } while (!sprite); + } + if (!sprite && iCurrentWindow && (iPointerCursorMode==EPointerCursorFixed || iPointerCursorMode==EPointerCursorNormal)) + { + sprite=CWsClient::DefaultSystemPointerCursor(); + } + return sprite; + } + +/* +Callback function for event queue walk +*/ +TEventQueueWalkRet PointerRepeatPurgeFunc(TAny* aReqPtrNum, TWsEvent* aQueueEvent) + { + return(TWsPointer::PointerRepeatPurgeCheck(aQueueEvent, reinterpret_cast(aReqPtrNum))); + } + +TBool TWsPointer::PointerEventRepeatCheck(const TWsEvent* aEvent, TUint32 aHandle) +// +// Return ETrue if this pointer event is consumed by the pointer repeat +// + { + // Must be a pointer event type in order to get the pointer number, + // which is needed to check the repeat window. + WS_ASSERT_DEBUG(aEvent->Type()==EEventPointer,EWsPanicEventType); + + const TAdvancedPointerEvent* pntEvent=aEvent->Pointer(); + if ( TAdvancedPointerEventHelper::PointerNumber(*aEvent)==iNumber && + aHandle==iRepeatWindow->ClientHandle()) + { + switch(pntEvent->iType) + { + case TPointerEvent::EDrag: // deliberate drop-through + case TPointerEvent::EMove: // deliberate drop-through + case TPointerEvent::EEnterCloseProximity: // deliberate drop-through + case TPointerEvent::EExitCloseProximity: // deliberate drop-through + case TPointerEvent::EEnterHighPressure: // deliberate drop-through + case TPointerEvent::EExitHighPressure: + { + if(iRepeatRect.Contains(pntEvent->iPosition)) + { + return(ETrue); + } + break; + } + default: + // do nothing and drop through + break; + } + } + return(EFalse); + } + +TEventQueueWalkRet TWsPointer::PointerRepeatPurgeCheck(TWsEvent* aQueueEvent, TUint8 aReqPtrNum) + { + // Return value is "WalkOK", unless a repeated event is found that needs to be deleted. + TEventQueueWalkRet eventQueueWalkRet(EEventQueueWalkOk); + + // Check the WSEvent Type + if (aQueueEvent->Type()==EEventPointer) // aEvent is a pointer event + { + // It is a pointer event, so we can get the pointer number + // to check if there is a repeat request for that pointer. + const TInt eventPtrNum(TAdvancedPointerEventHelper::PointerNumber(*aQueueEvent)); + // If aEvent's pointer has an active repeat request, + // then it'll have a repeat window. + if ((eventPtrNum == aReqPtrNum) && RepeatWindow(eventPtrNum)) + { + // There is a repeat request for the pointer. + // Is there a queued repeated event to be deleted? + TWsPointer& wsPointer = iPointers[eventPtrNum]; + if (wsPointer.PointerEventRepeatCheck(aQueueEvent,aQueueEvent->Handle())) + { + // Update the return value to purge the event + // as it is a move/drag within the repeat rect + eventQueueWalkRet=EEventQueueWalkDeleteEvent; + } + else + { + // No queued repeated event was found, therefore the + // request is still pending and needs to be cancelled. + wsPointer.CancelPointerRepeatEventRequest(); + } + } + } + return eventQueueWalkRet; + } + +void TWsPointer::RequestRepeatEvent(CWsWindow* aWindow, const TWsWinCmdRequestPointerRepeatEvent& aRequest) + { + CancelPointerRepeatEventRequest(); + iRepeatWindow=aWindow; + iRepeatRect=aRequest.rect; + iRepeatTimer->After(aRequest.time); + aWindow->EventQueue()->WalkEventQueue(&PointerRepeatPurgeFunc,reinterpret_cast(iNumber)); + if (iRepeatWindow && !iRepeatRect.Contains(iPos-iRepeatWindow->Origin())) + { + CancelPointerRepeatEventRequest(); + } + } + +TInt TWsPointer::RequestPointerRepeatEvent(CWsWindow* aWindow, const TWsWinCmdRequestPointerRepeatEvent& aRequest) + { + TInt errNo = KErrNone; + TUint8 pointerNum = aRequest.HasPointerNumber() ? aRequest.pointerNumber : iPrimaryPointer; + if(PointerNumberInRange(pointerNum)) + { + iPointers[pointerNum].RequestRepeatEvent(aWindow,aRequest); + } + else + { + errNo=KErrArgument; + } + return errNo; + } + +void TWsPointer::CancelPointerRepeatEventRequest() + { + if (iRepeatWindow) + { + iRepeatWindow=NULL; + if(iRepeatTimer) + iRepeatTimer->Cancel(); + } + } + +TInt TWsPointer::CancelPointerRepeatEventRequest(const TWsWinCmdCancelPointerRepeatEventRequest& aRequest) + { + TInt errNo = KErrNone; + TUint8 pointerNum = aRequest.HasPointerNumber() ? aRequest.pointerNumber : iPrimaryPointer; + if(PointerNumberInRange(pointerNum)) + { + iPointers[pointerNum].CancelPointerRepeatEventRequest(); + } + else + { + errNo=KErrArgument; + } + return errNo; + } + +void TWsPointer::RepeatTimerCompleted() + { + TWsEvent event; + event.SetType(EEventPointer); + event.SetTimeNow(); + TPoint3D point3D(iPos-iRepeatWindow->Origin()); + point3D.iZ=iPressureProximity; + TAdvancedPointerEventHelper::InitAdvancedPointerEvent(event, + TPointerEvent::EButtonRepeat, + TWindowServerEvent::GetModifierState(), + point3D, + (iPos-iRepeatWindow->BaseParent()->Origin()), + iNumber); + QueuePointerEvent(iRepeatWindow, event); + iRepeatWindow=NULL; + } + +#if defined(__WINS__) +void TWsPointer::SetXyInputType(TXYInputType aXyInputType) + { + if (iXyInputType>EXYInputPointer && aXyInputTypeEXYInputPointer) + { + // change from Pointer/None types to Mouse types + for (TInt ii = 0; ii < iMaxPointers; ii++) + { + if (iPointers[ii].iState != EPointerStateDown) + { + TPoint pos(iPointers[ii].iPos); + TPoint parPos; + iPointers[ii].ReLogCurrentWindow(pos,parPos,NULL); + } + } + UpdatePointerCursor(); + } + iXyInputType=aXyInputType; + } +#endif + +/** +Updates Primary Pointer before aRawEvent is processed. Only events related to Primary +Pointer will be sent to Clients which require single pointer environment. + +This method implements single pointer environment emulation rules (see design +documentation for more details). + +@param aRawEvent Incoming event used to update the Primary Pointer. It must be a pointer event, + as defined by TWsPointer::IsPointerEventType(TRawEvent::TType). +*/ +void TWsPointer::UpdatePrimaryPointer(const TRawEvent& aRawEvent) + { + iPreviousPrimaryPointer = iPrimaryPointer; + + TRawEvent::TType type=aRawEvent.Type(); + TInt pointerNumber = aRawEvent.PointerNumber(); + + // If primary pointer is out of range, then the first pointer that will + // start being detected (come back in range) will become primary. + if (iPointers[iPrimaryPointer].iState == EPointerStateOutOfRange) + { + if (type != TRawEvent::EPointer3DOutOfRange && iPointers[pointerNumber].iState == EPointerStateOutOfRange) + { + iPrimaryPointer = pointerNumber; + } + return; + } + + // if non-primary pointer sends EButton1Down event, and actual primary pointer + // is not down, then the pointer which has sent EButton1Down becomes primary. + if (type == TRawEvent::EButton1Down && + iPointers[iPrimaryPointer].iState != EPointerStateDown) + { + iPrimaryPointer = pointerNumber; + return; + } + } + +/** Sets Z coordinate threshold values for TPointerEvent::EEnterCloseProximity +and TPointerEvent::EExitCloseProximity events. +@return KErrNone if successful, + KErrNotSupported if the device doesn't support threshold values, + KErrArgument if aEnterCloseProximityThreshold is less than aExitCloseProximityThreshold +@see RWsSession::SetCloseProximityThresholds which calls this method +*/ +TInt TWsPointer::SetCloseProximityThresholds(TInt aEnterCloseProximityThreshold, TInt aExitCloseProximityThreshold) + { + if (aEnterCloseProximityThreshold < aExitCloseProximityThreshold) + { + return KErrArgument; + } + + TInt ret = HAL::Set(HALData::EPointer3DEnterCloseProximityThreshold, aEnterCloseProximityThreshold); + if (ret != KErrNone) + { + return ret; + } + + ret = HAL::Set(HALData::EPointer3DExitCloseProximityThreshold, aExitCloseProximityThreshold); + WS_ASSERT_DEBUG(ret == KErrNone, EWsPanicProxThresholdsInconsist); + if (ret != KErrNone) + { + HAL::Set(HALData::EPointer3DEnterCloseProximityThreshold, iEnterCloseProximityThreshold); + return ret; + } + + iEnterCloseProximityThreshold = aEnterCloseProximityThreshold; + iExitCloseProximityThreshold = aExitCloseProximityThreshold; + return KErrNone; + } + +/** +@return Z coordinate threshold value for TPointerEvent::EEnterCloseProximity events +@see RWsSession::GetEnterCloseProximityThreshold which calls this method +*/ +TInt TWsPointer::GetEnterCloseProximityThreshold() + { + return iEnterCloseProximityThreshold; + } + +/** +@return Z coordinate threshold value for TPointerEvent::EExitCloseProximity events +@see RWsSession::GetExitCloseProximityThreshold which calls this method +*/ +TInt TWsPointer::GetExitCloseProximityThreshold() + { + return iExitCloseProximityThreshold; + } + +/** Sets Z coordinate threshold value for TPointerEvent::EEnterHighPressure and +TPointerEvent::EExitHighPressure events. +@return KErrNone if successful, + KErrNotSupported if the device doesn't support threshold values, + KErrArgument if aEnterHighPressureThreshold is less than aExitHighPressureThreshold +@see RWsSession::SetHighPressureThresholds which calls this method +*/ +TInt TWsPointer::SetHighPressureThresholds(TInt aEnterHighPressureThreshold, TInt aExitHighPressureThreshold) + { + if (aEnterHighPressureThreshold < aExitHighPressureThreshold) + { + return KErrArgument; + } + + TInt ret = HAL::Set(HALData::EPointer3DEnterHighPressureThreshold, aEnterHighPressureThreshold); + if (ret != KErrNone) + { + return ret; + } + + ret = HAL::Set(HALData::EPointer3DExitHighPressureThreshold, aExitHighPressureThreshold); + WS_ASSERT_DEBUG(ret == KErrNone, EWsPanicPressThresholdsInconsist); + if (ret != KErrNone) + { + HAL::Set(HALData::EPointer3DEnterHighPressureThreshold, iEnterHighPressureThreshold); + return ret; + } + + iEnterHighPressureThreshold = aEnterHighPressureThreshold; + iExitHighPressureThreshold = aExitHighPressureThreshold; + return KErrNone; + } + +/** +@return Z coordinate threshold value for TPointerEvent::EEnterHighPressure events +@see RWsSession::GetEnterHighPressureThreshold which calls this method +*/ +TInt TWsPointer::GetEnterHighPressureThreshold() + { + return iEnterHighPressureThreshold; + } + +/** +@return Z coordinate threshold value for TPointerEvent::EExitHighPressure events +@see RWsSession::GetExitHighPressureThreshold which calls this method +*/ +TInt TWsPointer::GetExitHighPressureThreshold() + { + return iExitHighPressureThreshold; + } + + +/** +This function is specific for capacitive touch screens, where user's finger is the pointer device. +Usability studies have shown that the user's perception of the location of the pointer hit is always +away from few pixels north of the actual hit centre as detected by the digitizer device. So, this function +will shift all pointer events by a specified Y displacement. + +@param aY Current y coordinate pointer position. + + */ +void TWsPointer::ShiftYCoordinate(TInt& aY) + { + WS_ASSERT_DEBUG(iYOffset>=0, EWsPanicInvalidPointerOffset); + if (aY >= iYOffset) + { + aY -=iYOffset; + } + else + { + aY=0; + } + } +// +CWsPointerTimer::CWsPointerTimer(MPointerTimerCallback& aPointerTimerCallback) +: CTimer(EPointerRepeatPriority), iPointerTimerCallback(aPointerTimerCallback) + {} + +void CWsPointerTimer::ConstructL() + { + CTimer::ConstructL(); + CActiveScheduler::Add(this); + } + +CWsPointerTimer* CWsPointerTimer::NewL(MPointerTimerCallback& aWsPointer) + { + CWsPointerTimer* self = new(ELeave) CWsPointerTimer(aWsPointer); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(self); + return self; + } + +void CWsPointerTimer::RunL() + { + User::ResetInactivityTime(); + WS_ASSERT_DEBUG(iStatus.Int()==KErrNone, EWsPanicPointerRepeatTimerStatus); + iPointerTimerCallback.RepeatTimerCompleted(); + } +// + +CWsPointerBuffer::~CWsPointerBuffer() + { + if (this == iCurrentBuffer) + { + // We're about to be destroyed - don't want to be pointed at any more. + iCurrentBuffer = NULL; + } + iList.Remove(*this); + } + +void CWsPointerBuffer::ConnectL(CWsClientWindow* aWindow, TInt aMaxPoints, TUint aFlags) + { + CWsPointerBuffer* pb=NULL; + for(TSglQueIter iter(iList);(pb=iter++)!=NULL;) + { + if (pb->iWindow==aWindow) + { + User::Leave(KErrInUse); + } + } + CWsPointerBuffer* pbuf=new(ELeave) CWsPointerBuffer; + pbuf->iWindow=aWindow; + pbuf->iMaxPoints=aMaxPoints; + pbuf->iFlags=aFlags; + iList.AddFirst(*pbuf); + CleanupStack::PushL(pbuf); + AdjustMaxSizeL(); + CleanupStack::Pop(); + } + +void CWsPointerBuffer::Disconnect(CWsClientWindow* aWindow) + { + CWsPointerBuffer* pb=NULL; + for(TSglQueIter iter(iList);(pb=iter++)!=NULL;) + { + if (pb->iWindow==aWindow) + { + delete pb; // Note that the destructor also sets iCurrentBuffer to NULL if it is pointing at pb + TRAP_IGNORE(AdjustMaxSizeL()); // Shouldn't fail, but doesn't matter if it does as we simply have a larger buffer than needed + break; // from for loop + } + } + } + +void CWsPointerBuffer::Reset() + { + iSignalled=EFalse; + iPointerBuffer->Reset(); + } + +void CWsPointerBuffer::SignalBufferReady() + { + if (!iSignalled) + { + if (iCurrentBuffer && iCurrentBuffer->iWindow->QueueEvent(EEventPointerBufferReady)) + { + iSignalled=ETrue; + } + } + } + +void CWsPointerBuffer::PointerEvent(CWsClientWindow* aWindow,const TPoint &aPoint) + { + if (iCurrentBuffer==NULL || aWindow!=iCurrentBuffer->iWindow) + { + Reset(); + CWsPointerBuffer* pb=NULL; + for(TSglQueIter iter(iList);(pb=iter++)!=NULL;) + { + if (pb->iWindow==aWindow) + { + iCurrentBuffer=pb; + break; // from for loop + } + } + } + iPointerBuffer->Add(&aPoint); + SignalBufferReady(); + } + +void CWsPointerBuffer::RetrievePointerMoveBuffer(CWsClientWindow* aWindow,TInt aMaxPoints) + { + enum {KPointerMoveBufferSize=32}; // Puts 256 bytes on the stack + if (iCurrentBuffer && aWindow==iCurrentBuffer->iWindow) + { + iSignalled=EFalse; + TInt max=Min(aMaxPoints,iPointerBuffer->Count()); + TInt buflen=0; + aWindow->WsOwner()->SetReply(max); + TPoint point; + TBuf8 pnts; + for(TInt index=0;indexRemove(&point); + pnts.Append((TUint8 *)&point,sizeof(TPoint)); + buflen++; + if (buflen==KPointerMoveBufferSize) + { + CWsClient::ReplyBuf(pnts); + pnts.Zero(); + buflen=0; + } + } + if (buflen>0) + { + CWsClient::ReplyBuf(pnts); + } + if (iPointerBuffer->Count()) + { + SignalBufferReady(); + } + } + } + +void CWsPointerBuffer::DiscardPointerMoveBuffer(TUint aHandle) + { + if (iCurrentBuffer && aHandle==iCurrentBuffer->iWindow->ClientHandle()) + { + Reset(); + } + } + +void CWsPointerBuffer::DiscardPointerMoveBuffer(CWsClientWindow* aWindow) + { + if (iCurrentBuffer && aWindow==iCurrentBuffer->iWindow) + { + Reset(); + } + } + +void CWsPointerBuffer::AdjustMaxSizeL() + { + TInt max=0; + CWsPointerBuffer* pb=NULL; + for(TSglQueIter iter(iList);(pb=iter++)!=NULL;) + { + if (pb->iMaxPoints>max) + { + max=pb->iMaxPoints; + } + } + if (max==0) + { + delete iPointerBuffer; + iPointerBuffer=NULL; + } + else if (!iPointerBuffer) + { + CCirBuf* pointerBuffer=new(ELeave) CCirBuf; + CleanupStack::PushL(pointerBuffer); + pointerBuffer->SetLengthL(max); + CleanupStack::Pop(); + iPointerBuffer=pointerBuffer; + } + else + { + iPointerBuffer->SetLengthL(max); + } + }