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