windowing/windowserver/nga/SERVER/POINTER.CPP
changeset 0 5d03bc08d59c
child 2 5e30ef2e26cb
--- /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 <e32std.h>
+#include <e32hal.h>
+#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 <hal.h>
+#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> 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<TPoint>*   CWsPointerBuffer::iPointerBuffer=NULL;
+TSglQue<CWsPointerBuffer> 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<TWsPointer>(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))<iDoubleClickMaxDistance &&
+					aEvent.Time()<(iPrevClickTime+iDoubleClickMaxInterval))
+					{
+					aEvent.Pointer()->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.iTl.iX)
+		aPos.iX=validRect.iTl.iX;
+	else if (aPos.iX>=validRect.iBr.iX)
+		aPos.iX=validRect.iBr.iX-1;
+	if (aPos.iY<validRect.iTl.iY)
+		aPos.iY=validRect.iTl.iY;
+	else 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,&params);
+		}
+	}
+
+/*
+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<TUint>(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<TInt*>(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 && aXyInputType<EXYInputMouse)
+		{
+		// change from Mouse types to Pointer/None
+		for (TInt ii = 0; ii < iMaxPointers; ii++)
+			{
+			if (iPointers[ii].iState != EPointerStateDown)
+				{
+				iPointers[ii].iCurrentWindow=NULL;
+				}
+			}
+		UpdatePointerCursor();
+		}
+	else if (iXyInputType<EXYInputMouse && aXyInputType>EXYInputPointer)
+		{
+		// 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<CWsPointerBuffer> 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<CWsPointerBuffer> 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<CWsPointerBuffer> 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<KPointerMoveBufferSize*sizeof(TPoint)> pnts;
+		for(TInt index=0;index<max;index++)
+			{
+			iPointerBuffer->Remove(&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<CWsPointerBuffer> iter(iList);(pb=iter++)!=NULL;)
+		{
+		if (pb->iMaxPoints>max)
+			{
+			max=pb->iMaxPoints;
+			}
+		}
+	if (max==0)
+		{
+		delete iPointerBuffer;
+		iPointerBuffer=NULL;
+		}
+	else if (!iPointerBuffer)
+		{
+		CCirBuf<TPoint>* pointerBuffer=new(ELeave) CCirBuf<TPoint>;
+		CleanupStack::PushL(pointerBuffer);
+		pointerBuffer->SetLengthL(max);
+		CleanupStack::Pop();
+		iPointerBuffer=pointerBuffer;
+		}
+	else
+		{
+		iPointerBuffer->SetLengthL(max);
+		}
+	}