/*
* Copyright (c) 2005-2007 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:  Implementation for peninput animation dll
*
*/


/*
* ============================================================================
*
* Refactoring by Steven Yao
* 
* 2007-03-23
*
* ============================================================================
*/

//INCLUDE
#include "peninputanim.h" 
#include "peninputcmdparam.h"
#include "peninputcmdparamext.h"
#include "peninputcmd.h"
#include "penpointereventsuppressor.h"
// ----------- Touch feedback additions start
#ifdef RD_TACTILE_FEEDBACK
#include <coecntrl.h>
#include <tactilefeedbackserver.h>
#include <featmgr.h>
#endif //RD_TACTILE_FEEDBACK
// ----------- Touch feedback additions start

#include <avkondomainpskeys.h>
//CONSTANT
const TInt KMsgSlot1 = 1;     //msg slot 2 in IPC
const TInt KMsgSlot2 = 2;     //msg slot 2 in IPC
const TInt KFlushTimerPeriod = 1000 * 10;          //1/100 second
const TInt KResponseQueueWaitTime = 100000;        //1/10 second

// ======== GLOBAL FUNCTIONS ========

// ---------------------------------------------------------------------------
// CreateCAnimDllL
// This is called by the window server, at the request of the animation 
// client, to construct the CAnimDll derived server side DLL class.
// ---------------------------------------------------------------------------
//
EXPORT_C CAnimDll *CreateCAnimDllL()
    {
    return(new (ELeave) CPeninputAnimDll()); 
    }

// ======== MEMBER FUNCTIONS ========

// class CAnimDll

// ---------------------------------------------------------------------------
// CPeninputAnimDll::CreateInstanceL
// Factory function for animation DLL.
// ---------------------------------------------------------------------------
//
CAnim* CPeninputAnimDll::CreateInstanceL(TInt /*aType*/)
    {
    return new(ELeave) CPeninputAnim();
    }

// class CPeninputAnim

// ---------------------------------------------------------------------------
// CPeninputAnim::CPeninputAnim
// Constructor
// ---------------------------------------------------------------------------
//
CPeninputAnim::CPeninputAnim()
    {
    iIsActive = EFalse;
    //iSpritePosition and iSpriteSize are initialized to 0 by default constructor
    //iSpritePosition = TPoint(0, 0);
    //iSpriteSize = TSize(0, 0);
    iIsPointerCaptured = EFalse;
    iIsPenDown = EFalse;
    
    iPrimaryTouchPtNum = 0;
    iPrimaryTouchPtDetected = EFalse;

    
#ifdef RD_TACTILE_FEEDBACK    
    TRAPD( err, FeatureManager::InitializeLibL() );
    if( err == KErrNone )
        {
        iTactileSupported =  FeatureManager::FeatureSupported( KFeatureIdTactileFeedback );
        }
    iFeedback = MTactileFeedbackServer::Instance();
#endif // RD_TACTILE_FEEDBACK    
    
    iEnableSprite = ETrue;    
    iDSAState = EFalse;    
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::~CPeninputAnim
// Destructor
// ---------------------------------------------------------------------------
//
CPeninputAnim::~CPeninputAnim()
    {
    Deactivate();

    iMsgBufQueue.Close();
    iKeyMsgResponseQueue.Close();
    iResponseQueueSemaphore.Close();
    
    delete iFlushTimer;
#ifdef RD_TACTILE_FEEDBACK    
    FeatureManager::UnInitializeLib();
    iTactileControl.Close();
    iBackupTactileControl.Close();
#endif // RD_TACTILE_FEEDBACK    
    delete iPointerEventSuppressor;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::ConstructL
// Second phase constructor
// ---------------------------------------------------------------------------
//
void CPeninputAnim::ConstructL(TAny* /*aParameters*/)
    {
    // the animation feature is not used
    iFunctions->SetInterval(0);
    iFlushTimer = CPeriodic::NewL(CActive::EPriorityStandard);
    
    iFunctions->RegisterForNotifications(EDirectScreenAccess);
    iPointerEventSuppressor = CPenPointerEventSuppressor::NewL();
    }


// ---------------------------------------------------------------------------
// CPeninputAnim::Animate
// Create layout
// ---------------------------------------------------------------------------
//
void CPeninputAnim::Animate(TDateTime* /*aDateTime*/)
    {
    // do nothing
    }


void CPeninputAnim::HandleNotification(const TWsEvent& aEvent)
    {
    switch (aEvent.Type())
        {
        case EEventDirectScreenAccessBegin:
            SetDSAState(ETrue);
            break;
        case EEventDirectScreenAccessEnd:
            SetDSAState(EFalse);
            break;
        default:
            break;
        }
    }
    
void CPeninputAnim::SetDSAState(TBool aFlag)
    {
    iDSAState = aFlag;
    if(aFlag && iEnableSprite) //close sprite when DSA is on
        {
        TRawEvent event;
        event.Set( TRawEvent::ENone );
        event.SetTip( ETrue );
        PostRawEvent( event );
        FlushRawEventBuffer();
        //Deactivate(); 
        //iEnableSprite = EFalse;
        }
    /*else
        {
        iEnableSprite = iESPrevState;
        }*/
    }
// ---------------------------------------------------------------------------
// CPeninputAnim::OfferRawEvent
// handle raw events, e.g. key presses, pen events, power buttons etc. 
// if the event can be handled then return ETrue, or return EFalse
// ---------------------------------------------------------------------------
//
TBool CPeninputAnim::OfferRawEvent(const TRawEvent& aRawEvent)
    {
    if( iIsSimulatedEvent )
        {
        return EFalse;
        }
    
    // Suppress multi-touch events
    switch ( aRawEvent.Type() )
        {
        case TRawEvent::EButton1Down:
        case TRawEvent::EButton1Up:
        case TRawEvent::EPointerMove:
            {
            if ( iPrimaryTouchPtDetected )
                {
                if ( aRawEvent.PointerNumber() != iPrimaryTouchPtNum )
                    {
                    return ETrue;
                    }
                }
            else
                {
                iPrimaryTouchPtNum = aRawEvent.PointerNumber();
                iPrimaryTouchPtDetected = ETrue;
                }
            }
            break;
        default:
            break;
        }

    
    // Suppress unexpected drag events
    TPointerEvent pointerEvent;
    switch ( aRawEvent.Type() )
        {
        case TRawEvent::EButton1Down:
            {
            pointerEvent.iType = TPointerEvent::EButton1Down;
            pointerEvent.iPosition = aRawEvent.Pos();
            break;
            }
        case TRawEvent::EButton1Up:
            {
            pointerEvent.iType = TPointerEvent::EButton1Up;
            pointerEvent.iPosition = aRawEvent.Pos();
            break;
            }
        case TRawEvent::EPointerMove:
            {
            pointerEvent.iType = TPointerEvent::EDrag;
            pointerEvent.iPosition = aRawEvent.Pos();
            break;
            }
        default:
            pointerEvent.iType = TPointerEvent::ENullType;
        }
    
    TBool result = iPointerEventSuppressor->SuppressPointerEvent( pointerEvent );
    if ( result )
        {
        return ETrue;
        }

    TRawEvent rawEvent = aRawEvent;
    if ( aRawEvent.Type() == TRawEvent::EButton1Up 
         && aRawEvent.Pos() != pointerEvent.iPosition )
        {
        rawEvent.Set( TRawEvent::EButton1Up, 
                      pointerEvent.iPosition.iX, 
                      pointerEvent.iPosition.iY );
        }
    
    switch(aRawEvent.Type())
        {
        case TRawEvent::EKeyUp:
        case TRawEvent::EKeyDown:
            {
            return OnRawKeyEvent( rawEvent );            
            }
        case TRawEvent::EButton1Down:
            {
            TBool used = OnRawButton1Down( rawEvent );
            
            if ( used )
                {
                StartTimer();
                }
            
            return used;
            }
        case TRawEvent::EButton1Up:
            {
            TBool used = OnRawButton1Up( rawEvent );
            StopTimer();
            return used;
            }
        case TRawEvent::EPointerMove:
            {
            return OnRawPointerMove( rawEvent );
            }
        default:
            {
            return EFalse;
            }
        }
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::Command
// The window server calls this function in response to application 
// calls to the client side command function RAnim::Command()
// ---------------------------------------------------------------------------
//
void CPeninputAnim::Command(TInt aOpcode, TAny* aParams)
    {
    switch(aOpcode)
        {
        case EPeninputOpActivate:
            {
            Activate();
            break;
            }        
        case EPeninputOpDeactivate:
            {
            Deactivate();
            break;
            }        
        case EPeninputOpLayoutUpdateArea:
            {
            PanicClientIfNoParam(aParams);                    
            TUpdateDataArea* area = static_cast<TUpdateDataArea*>(aParams);
            iSpriteFunctions->UpdateMember( 0, area->iRect, area->iUpdateFlag );
            break;
            }            
        case EPeninputOpCapturePointer:
            {
            PanicClientIfNoParam(aParams);            
            iIsPointerCaptured = *(static_cast<TBool*>(aParams));
            break;
            }
        case EPeninputOpSimulateEvent:
            {
            PanicClientIfNoParam(aParams);
            TRawEvent event = *(static_cast<TRawEvent*>(aParams));
            iIsSimulatedEvent = ETrue;
            iFunctions->PostRawEvent(event);
            iIsSimulatedEvent = EFalse;

            break;
            }

#ifdef RD_TACTILE_FEEDBACK         
        case EPeninputOpRegisterFeedbackArea:
            {
            //add the rect to feedback list
            PanicClientIfNoParam(aParams);
            TTactileFeedbackArea area = *(static_cast<TTactileFeedbackArea*>(aParams));
            
            //Advanced Tactile feedback REQ417-47932
            TTactileControlInfo controlitem(area.iId, area.iNewRect, area.iTactileType);
            iTactileControl.Append(controlitem); 
            }
            break;
        case EPeninputOpDeRegisterFeedbackArea:
            {
            PanicClientIfNoParam(aParams);
            TTactileFeedbackArea area = *(static_cast<TTactileFeedbackArea*>(aParams));
            const TInt KRemoveAllId = -1;
            
            if( area.iId == KRemoveAllId && area.iNewRect == TRect(0,0,0,0) )
                {
                //remove all
                iTactileControl.Reset();
                break;
                }
            TTactileControlInfo controlitem(area.iId, area.iNewRect, area.iTactileType);
            TInt idx = iTactileControl.Find(controlitem, 
                    TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlID));
            if(idx != KErrNotFound)
                {  
                iTactileControl.Remove(idx);
                }
            }
            break;  
        case EPeninputOpChangeFeedbackArea:
            {
            PanicClientIfNoParam(aParams);
            TTactileFeedbackArea area = *(static_cast<TTactileFeedbackArea*>(aParams));
            TTactileControlInfo controlitem(area.iId, area.iPrevRect, area.iTactileType);           
            TInt idx = iTactileControl.Find(controlitem, 
                    TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlIDAndArea));
            if(idx != KErrNotFound)
                {                                
                //change the rect
                iTactileControl[idx].iArea = area.iNewRect;
                }  
            }
            break; 
        case EPeninputOpChangeFeedbackType:
            {
            PanicClientIfNoParam(aParams);
            TTactileFeedbackArea area = *(static_cast<TTactileFeedbackArea*>(aParams));
            TTactileControlInfo controlitem(area.iId, area.iNewRect, area.iTactileType);
            TInt idx = iTactileControl.Find(controlitem,                    
                    TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlID));
            if(idx != KErrNotFound)
                {                                
                //change the tactile type
                iTactileControl[idx].iTactileType = area.iTactileType;
                }            
            }
            break;
#endif // RD_TACTILE_FEEDBACK
        case EPeninputOpEnalbeSprite:
            {
            PanicClientIfNoParam(aParams);
            iEnableSprite = *(static_cast<TBool*>(aParams));            
            }
            break;
          

        default:
            {
            //panic the client for unknown command
            iFunctions->Panic();
            break;
            }
        }
    }


// ---------------------------------------------------------------------------
// CPeninputAnim::CommandReplyL
// The window server calls this function in response to application calls 
// to the client side command function RAnim::CommandReplyL(). 
// This function can't leave. Otherwise window server panic
// ---------------------------------------------------------------------------
//
TInt CPeninputAnim::CommandReplyL( TInt aOpcode, TAny* /*aParams*/)
    {
    TInt retValue = KErrNone;
    const RMessagePtr2* msg = iFunctions->Message();
    switch ( aOpcode )
        {
        case EPeninputOpFinishConstructionL:
            {
            iFunctions->SetSync( MAnimGeneralFunctions::ESyncNone );
            
            retValue = iMsgBufQueue.OpenGlobal(KMsgEventBufferQueue);
            //event queue for key event response from pen input servers
            iKeyMsgResponseQueue.OpenGlobal(KMsgEventResponseQueue);
            iResponseQueueSemaphore.OpenGlobal(KAnimKeyEventSemaphore);

            break;
            }

        case EPeninputOpActivate:
            {
            Activate();
            break;
            }
        
        case EPeninputOpDeactivate:
            {
            Deactivate();
            break;
            }       
            
        case EPeninputOpLayoutUpdateArea:
            {
            //TUpdateDataArea s;
            //TPckg<TUpdateDataArea> pkg(s);            
            TRect rect;
            TBool flag;
            TPckg<TRect> rectMsg(rect);            
            TPckg<TBool> flagMsg(flag);    
            
            msg->ReadL(KMsgSlot1,rectMsg);
            msg->ReadL(KMsgSlot2,flagMsg);
            iSpriteFunctions->UpdateMember(0, rect,flag);            
              }
              break;
        case EPeninputOpLayoutUpdateAreaRegion:
            {
            TInt num;
            TPckg<TInt> numMsg(num);    
            msg->ReadL(KMsgSlot1,numMsg);
            TInt len = msg->GetDesLengthL(KMsgSlot2);
            TUint8* buf = new (ELeave) TUint8[len*sizeof(TUpdateArea)];
            CleanupArrayDeletePushL( buf );
            
            TPtr8 ptr(buf,len);
            msg->ReadL(KMsgSlot2,ptr);

            TUpdateArea* area = reinterpret_cast<TUpdateArea*>(buf);

            for(TInt i = 0; i < num; ++i)
                {
                iSpriteFunctions->UpdateMember(0, area[i].iRect,area[i].iFullUpdateFlag);
                }

            CleanupStack::PopAndDestroy( buf );
            }
            break;
        case EPeninputOpSetLayoutPos:
            {
            TPoint pt;
            TPckg<TPoint> msgData(pt);
            msg->ReadL(KMsgSlot1,msgData);
            SetPosition(pt);            
            }
            break;
            
        case EPeninputOpCapturePointer:
            {
            TInt captureCtrlID;
            TPckg<TBool> msgData(iIsPointerCaptured);
            TPckg<TInt> msgCaptureCtrlIDData(captureCtrlID);
            
            msg->ReadL(KMsgSlot1,msgData);
            msg->ReadL(KMsgSlot2,msgCaptureCtrlIDData);
#ifdef RD_TACTILE_FEEDBACK
            // When pointer is captured by some ctrl,
            // only the captured ctrl has tactile feedback ablity,
            // disable all other one's.
            if (iIsPointerCaptured)
                {
                // Back up all the tactile area
                iBackupTactileControl.Reset();            
                TInt count = iTactileControl.Count();
                for(TInt i = 0; i < count; ++i)
                    {
                    iBackupTactileControl.Append(iTactileControl[i]);
                    }
                
                // Clean up the original tactile area
                iTactileControl.Reset();               
                
                // Find the captured ctrl, restore its tactile ablity
                for(TInt i = 0; i < count; ++i)
                    {
                    if (iBackupTactileControl[i].iId == captureCtrlID)
                        {
                        iTactileControl.Append(iBackupTactileControl[i]);
                        }
                    }

                }
            // When pointer released captured, 
            // restore all original tactile area.
            else 
                {
                if (iBackupTactileControl.Count() != 0)
                    {
                    iTactileControl.Reset();                   
                    
                    TInt count = iBackupTactileControl.Count();
                    for(TInt i = 0; i < count; ++i)
                        {
                        iTactileControl.Append(iBackupTactileControl[i]);
                        }
                    iBackupTactileControl.Reset();
                    }
                }
#endif                
            }
            break;
        case EPeninputOpLayoutSizeChangedWithSize:
                {
                TPckg<TSize> msgData(iSpriteSize);
                msg->ReadL(1,msgData); 
                iSpriteFunctions->SizeChangedL();
                }
            break;
        case EPeninputOpSimulateEvent:
            {
            TRawEvent event;
            TPckg<TRawEvent> msgData(event);
            msg->ReadL(KMsgSlot1,msgData); 
            iIsSimulatedEvent = ETrue;
            iFunctions->PostRawEvent(event);
            iIsSimulatedEvent = EFalse;
            
            }
            break;    
            
#ifdef RD_TACTILE_FEEDBACK             
        case EPeninputOpRegisterFeedbackArea:
            {                        
            GetFeedbackAreaDataL(iTactileControl,msg);            
            }
            break;
            
        case EPeninputOpDeRegisterFeedbackArea:
            {
            //Advanced Tactile feedback REQ417-47932
            RArray<TTactileControlInfo> controlarray;
            CleanupClosePushL(controlarray);
            
            GetFeedbackAreaDataL(controlarray,msg);
            
            //remove all registered feedback area
            const TInt KRemoveAllId = -1;           
            if(controlarray.Count() && controlarray[0].iId == KRemoveAllId && 
                                        controlarray[0].iArea == TRect(0,0,0,0))
                {
                //remove all
                iTactileControl.Reset();
                }
            else
                {
                //remove the area
                for(TInt i = 0; i < controlarray.Count(); ++i)
                    {
                    //find id first
                    TInt idx = iTactileControl.Find(controlarray[i], 
                                TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlID));
                    
                    if(idx != KErrNotFound)
                        {
                        iTactileControl.Remove(idx);                       
                        }
                    }
                }
                
            CleanupStack::PopAndDestroy( 1, &controlarray );
            }
            break;
        
            
        case EPeninputOpChangeFeedbackArea:            
            {
            //Advanced Tactile feedback REQ417-47932
            RArray<TTactileControlInfo> controlarray;
            RArray<TRect> prevArea;
            
            CleanupClosePushL(controlarray);
            CleanupClosePushL(prevArea);
            
            GetFeedbackAreaDataL(controlarray,msg,&prevArea);
            //change the area one by one            
            for(TInt i = 0; i < controlarray.Count(); ++i)
                {
                //find id first
                TInt idx = iTactileControl.Find(controlarray[i], 
                           TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlID));
                                    
                if(idx != KErrNotFound)
                    {
                    //check the rect
                    if(prevArea[i] == iTactileControl[idx].iArea)
                        {
                        //change the rect
                        iTactileControl[idx].iArea = controlarray[i].iArea;
                        break;
                        }
                    }
                }
            
            CleanupStack::PopAndDestroy( 2, &controlarray );
            }
        
            break;
            
        //Advanced Tactile feedback REQ417-47932    
        case EPeninputOpChangeFeedbackType:            
            {           
            RArray<TTactileControlInfo> controlarray;
            CleanupClosePushL(controlarray);
            
            GetFeedbackAreaDataL(controlarray,msg);
            //change the area one by one
            for(TInt i = 0; i < controlarray.Count(); ++i)
                {
                //find id first
                TInt idx = iTactileControl.Find(controlarray[i],                            
                           TIdentityRelation<TTactileControlInfo>(CPeninputAnim::MatchItemByControlID));
                if(idx != KErrNotFound)
                    {
                    //change the tactile feedback type
                    iTactileControl[idx].iTactileType = controlarray[i].iTactileType;
                    break;
                    }
                }
            
            CleanupStack::PopAndDestroy( 1, &controlarray );
            }
  
            break;
            
#endif // RD_TACTILE_FEEDBACK 
        case EPeninputOpRequestDSAState:                        
            {
            TPckgC<TBool> flagMsg(iDSAState);    
            
            msg->WriteL(KMsgSlot1,flagMsg);
            
            }
            break;
        case EPeninputOpSetDiscreeptPop:
            {
            TRect area;
            TPckg<TRect> msgData(area);
            msg->ReadL(KMsgSlot1,msgData);
            SetDiscreeptPop(area); 
            }
            break;
        case EPeninputOpUpdatePointerSuppressor:
            {
            TPointerEventSuppressorParameters parameters;
            TPckg<TPointerEventSuppressorParameters> msgData( parameters );
            msg->ReadL( KMsgSlot1, msgData );
            
            iPointerEventSuppressor->SetMaxTapMove( parameters.iMoveEventMaxMovement );
            iPointerEventSuppressor->SetMaxTapDuration( parameters.iMoveEventTimeout );
            iPointerEventSuppressor->SetMaxDownUpMove( parameters.iUpEventMaxMovement );
            iPointerEventSuppressor->SetMaxDownUpDuration( parameters.iUpEventTimeout );
            }
            break;
        default:
            // unsupported opcode, panic the client
            {                
            iFunctions->Panic();
            retValue = KErrNotSupported;
            }
            break;
        }

    return retValue;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::Activate
// Makes PENINPUT window visible
// ---------------------------------------------------------------------------
//
void CPeninputAnim::Activate()
    {
    if(!iIsActive)
        {
        iSpriteFunctions->SetPosition(iSpritePosition);
        if(iEnableSprite)
            iSpriteFunctions->Activate(ETrue);
        iFunctions->GetRawEvents(ETrue);
        iIsActive = ETrue;        
        }        
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::Deactivate
// Makes PENINPUT window invisible
// ---------------------------------------------------------------------------
//
void CPeninputAnim::Deactivate()
    {
    if(iIsActive)
        {
        if(iEnableSprite)
            iSpriteFunctions->Activate(EFalse);
        iFunctions->GetRawEvents(EFalse);        
        iIsActive = EFalse;
        
        StopTimer();
        }        
    }
    
#ifdef RD_TACTILE_FEEDBACK
// ---------------------------------------------------------------------------
// CPeninputAnim::DoTactileFeedBack
// Give tactile feedback
// ---------------------------------------------------------------------------
//                        
void CPeninputAnim::DoTactileFeedBack(const TPoint& aPos)
    {
    if ( iFeedback ) 
        {
        TInt count = iTactileControl.Count();
        for(TInt i = 0; i < count; ++i)
            {
            if(iTactileControl[i].iArea.Contains(aPos))
                {
                iFeedback->InstantFeedback((TTouchLogicalFeedback)iTactileControl[i].iTactileType);
                return;
                }                 
            }           
        }
    }
#endif // RD_TACTILE_FEEDBACK

// ---------------------------------------------------------------------------
// CPeninputAnim::OnRawButton1Down
// Handles raw pen down events
// Can't leave, since this is run in window server side.
// return value indicating whether the event was handled by this function    
// ---------------------------------------------------------------------------
//

TBool CPeninputAnim::OnRawButton1Down(const TRawEvent& aRawEvent)
    {
    if(iIsSimulatedEvent)
        {
        return EFalse;
        }
        
    
    if(iDiscreetPoped && iDiscreetPopArea.Contains(aRawEvent.Pos()))
        {
        iDiscreetPopedCapture = ETrue;
        return EFalse;
        }
    TRect rect(iSpritePosition, iSpriteSize);        
    if(rect.Contains(aRawEvent.Pos()))
        {                
#ifdef RD_TACTILE_FEEDBACK            
        //give tactile feedback        
        if(iTactileSupported)
            DoTactileFeedBack(aRawEvent.Pos() - rect.iTl);
#endif // RD_TACTILE_FEEDBACK    
        iIsPenDown = ETrue;

        // When button downing event is happened, iIsMove is reset to EFalse
        iIsMove = EFalse;              

        // Recording pointer that button is pressing down in at this time
        iPointerDown = aRawEvent.Pos();  
        //

        PostRawEvent(aRawEvent); 
        return ETrue;
        }

    if(iIsPointerCaptured)
        {                    
        PostRawEvent(aRawEvent);
        return ETrue;
        }

    //pointer outside of input area,inform layout
    SendRawEvent(aRawEvent);

    return EFalse;
    }

TBool CPeninputAnim::OnRawButton1Up(const TRawEvent& aRawEvent)
    {
    if(iIsSimulatedEvent)
        {
        return EFalse;
        }

    //For discreetPop
    if(iDiscreetPopedCapture )
        {
        iDiscreetPopedCapture = EFalse;
        return EFalse;
        }
    if(iIsPenDown)
        {      
  
        // When the control key pressing down in is different with the control key pressing up 
        // and pointer moving event isn¡¯t happened,
        // pointer moving event will is supplied 
        if(iPointerDown != aRawEvent.Pos() && !iIsMove)
          {
          TRawEvent rawEvent = aRawEvent;
          rawEvent.Set( TRawEvent::EPointerMove );
          OnRawPointerMove(rawEvent);
          }
        //

        iIsPenDown = EFalse;
        
        TRect rect(iSpritePosition, iSpriteSize);        
        if(rect.Contains(aRawEvent.Pos()))
            {
            //send pen up event immediately
            SendRawEvent(aRawEvent);
            
            // When key pressing up event is completed, iIsMove is reset to EFalse.
            iIsMove = EFalse;   
            //

            return ETrue;                    
            }
        }
    
    if(iIsPointerCaptured)
        {                    
        PostRawEvent(aRawEvent);
        return ETrue;
        }
    
    //pointer outside of input area,inform layout
    SendRawEvent(aRawEvent);

    return EFalse;    
    }

TBool CPeninputAnim::OnRawPointerMove(const TRawEvent& aRawEvent)
    {
    if(iIsSimulatedEvent)
        {
        return EFalse;
        }
    if(iDiscreetPopedCapture)
        {
        return EFalse;
        }
#ifdef RD_TACTILE_FEEDBACK            
    TRect rect(iSpritePosition, iSpriteSize);        
    if( iIsPenDown && iIsPointerCaptured)
        {                
        //give tactile feedback        
        // When pointer moving event is happened, iIsMove is set to ETrue
        iIsMove = ETrue;        
        //

        PostRawEvent(aRawEvent); 
        return ETrue;
        }
#endif // RD_TACTILE_FEEDBACK    

    if(iIsPointerCaptured || iIsPenDown)
        {                    
        // When pointer moving event is happened, iIsMove is set to ETrue
        iIsMove = ETrue;        
        //

        PostRawEvent(aRawEvent);
        return ETrue;
        }
    
    return EFalse;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::SetPosition
// called when sprite has been moved
// ---------------------------------------------------------------------------
//

TPoint CPeninputAnim::SetPosition(const TPoint& aNewPos)
    {
    if(aNewPos != iSpritePosition)
        {
        iSpritePosition = aNewPos;
        iSpriteFunctions->SetPosition(iSpritePosition);    
        }
    return iSpritePosition;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::UpdateArea
// Update sprite rect
// ---------------------------------------------------------------------------
//
void CPeninputAnim::UpdateArea(const TRect& aRect, TBool aFullUpdate)
    {
    if(iIsActive)
        {
        // if function is called without specifying the parameter aRect
        // (using default param value) the whole area drawn to is updated
        iSpriteFunctions->UpdateMember(0, aRect, aFullUpdate);
        }
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::TimerCallBack
// Callback function of CPeriodic
// ---------------------------------------------------------------------------
//
TInt CPeninputAnim::FlushTimerCallBack(TAny* aPtr)
    {
    CPeninputAnim* self = static_cast<CPeninputAnim*>(aPtr);            
    self->FlushRawEventBuffer();            
    return KErrNone;
    }
  
// ---------------------------------------------------------------------------
// CPeninputAnim::SendRawEvent
// Send event to pen input server by buffering it
// ---------------------------------------------------------------------------
//    
void CPeninputAnim::SendRawEvent(const TRawEvent& aRawEvent)
    {
    //save to buffer first
    iEventBuffer.iEvent[iEventBuffer.iNum] = aRawEvent;
    iEventBuffer.iNum++;

    FlushRawEventBuffer();
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::PostRawEvent
// Save the event to the buffer
// ---------------------------------------------------------------------------
//        
void CPeninputAnim::PostRawEvent(const TRawEvent& aRawEvent)
    {
    if(iEventBuffer.iNum >= KMaxEvent)
        {
        FlushRawEventBuffer();
        }
    
    iEventBuffer.iEvent[iEventBuffer.iNum] = aRawEvent;
    iEventBuffer.iNum++;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::FlushRowEventBuffer
// Send pointer event to pen input serrver, and return error code
// ---------------------------------------------------------------------------
//
TInt CPeninputAnim::FlushRawEventBuffer()
    {
    TInt ret = KErrNone;
    
    if(iEventBuffer.iNum > 0)
        {
        ret = iMsgBufQueue.Send(iEventBuffer);
           iEventBuffer.iNum = 0;            
        }
    
    return ret;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::OnRawKeyEvent
// Send raw key event to pen input server for processing.
// Wait until it's processed or timer out
// ---------------------------------------------------------------------------
//    
TBool CPeninputAnim::OnRawKeyEvent(const TRawEvent& aRawEvent)
    {
    TInt ret = KErrNone;
    
    //first sends all buffered event out
    FlushRawEventBuffer();
    
    //clear the signal and the response msg queue
    TBool isHandled = EFalse;
    ret = iKeyMsgResponseQueue.Receive(isHandled);
    while(ret == KErrNone)
        {
        iResponseQueueSemaphore.Wait();
        ret = iKeyMsgResponseQueue.Receive(isHandled);
        }

    //send the event directly        
    iEventBuffer.iNum = 1;
    iEventBuffer.iEvent[0] = aRawEvent;
    ret = FlushRawEventBuffer();
    
    isHandled = EFalse;
    if(ret == KErrNone) 
        {
        //wait for the key event processed.    
        ret = iResponseQueueSemaphore.Wait(KResponseQueueWaitTime);
        if(ret == KErrNone)
            {        
            //read the response from msg queue
            iKeyMsgResponseQueue.Receive(isHandled);
            }
        }

    return isHandled;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::StartTimer
// Initial and start timer
// ---------------------------------------------------------------------------
// 
void CPeninputAnim::StartTimer()
    {
    if ( iIsActive && !iFlushTimer->IsActive())
        {
        iFlushTimer->Start(
            KFlushTimerPeriod, 
            KFlushTimerPeriod, 
            TCallBack(FlushTimerCallBack, this));
        }
    }
    
// ---------------------------------------------------------------------------
// CPeninputAnim::StopTimer
// Cancel timer
// ---------------------------------------------------------------------------
// 
void CPeninputAnim::StopTimer()
    {
    iFlushTimer->Cancel();
    FlushRawEventBuffer();
    }

#ifdef RD_TACTILE_FEEDBACK
void CPeninputAnim::GetFeedbackAreaDataL(RArray<TTactileControlInfo>& aTactileControlArray,
                                         const RMessagePtr2* msg, 
                                         RArray<TRect>* aPrevRectArray)
    {
    TInt num;
    TPckg<TInt> numBuf(num);
    msg->ReadL(KMsgSlot1,numBuf);
    TTactileFeedbackArea* area = new(ELeave) TTactileFeedbackArea[num];

    CleanupArrayDeletePushL( area );

    TPtr msgData(reinterpret_cast<TUint16*>(area), num*sizeof(TTactileFeedbackArea)/2);
    msg->ReadL(KMsgSlot2,msgData);           
            
    for(TInt i = 0 ; i < num; ++i)
        {
        //Advanced Tactile feedback REQ417-47932
        aTactileControlArray.Append(TTactileControlInfo(area[i].iId,
                                    area[i].iNewRect,area[i].iTactileType));      
        //aRectArray.Append(area[i].iNewRect);                
        if(aPrevRectArray)
            aPrevRectArray->Append(area[i].iPrevRect);                    
        }

    CleanupStack::PopAndDestroy( area );            
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::MatchItemByControlID
// Compare the Item by ID
// ---------------------------------------------------------------------------
// 
TBool CPeninputAnim::MatchItemByControlID (const TTactileControlInfo& aFirst, const TTactileControlInfo& aSecond)
    {
    if (aFirst.iId == aSecond.iId)
        return ETrue;
    return EFalse;
    }

// ---------------------------------------------------------------------------
// CPeninputAnim::MatchItemByControlIDAndArea
// Compare the Item by ID and Area
// ---------------------------------------------------------------------------
// 
TBool CPeninputAnim::MatchItemByControlIDAndArea (const TTactileControlInfo& aFirst, const TTactileControlInfo& aSecond)
    {
    if ((aFirst.iId == aSecond.iId) && (aFirst.iArea == aSecond.iArea))
        return ETrue;
    return EFalse;
    }
#endif // RD_TACTILE_FEEDBACK    

void CPeninputAnim::SetDiscreeptPop(TRect aArea)
    {
    iDiscreetPopArea = aArea;
    if(iDiscreetPopArea.Size().iWidth > 0)
        {
        iDiscreetPoped = ETrue;
        }    
    else
        {
        iDiscreetPoped = EFalse;
        iDiscreetPopedCapture = EFalse;
        }
    }
// End of File
