diff -r d39add9822e2 -r 5bfc169077b2 webengine/webkitutils/stmgesturefw/src/stateengine.cpp --- a/webengine/webkitutils/stmgesturefw/src/stateengine.cpp Tue Feb 02 00:56:45 2010 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1159 +0,0 @@ -/* -* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). -* All rights reserved. -* This component and the accompanying materials are made available -* under the terms of the License "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: -* -*/ - - -#include "stateengine.h" -#include "utils.h" -#include "uievent.h" -#include "uieventsender.h" -#include "filelogger.h" -//#include "flogger.h" - -using namespace stmUiEventEngine ; - -/*! - State definitions glue together the methods of the stateengine.cpp - so that it will behave as defined in the state machine specification. - First define the separate elements for each possible event and then tie them together - to create one state entry. The state entries then are put to array - where the index is at the same time also the state ID. - - STATE_ELEMENT arrays define the methods called when handling a message. - \sa STATE_ELEMENT. - Note that the last row of STATE_ELEMENT array must NOT have a ConditionFunction entry - and it must have a NextState entry != Eignore. Otherwise the state machine will - not behave correctly. - - */ -/*! Add macro with token pasting to make creation of the state machine tables easier - and removing the necessity to write the classname twice. - Maybe there would be some better way to do this using templates and typedefs? - */ -#define CND(x) isF -#define ACT(x) aF - -/********************************************************************************* - * empty statedef as a dummy entry - * */ -const STATE_ELEMENT __ErrorEvent[1] = { - 0, - ACT(ErrorEvent), - EInit -}; - -const STATE Ignore__[1] = { - EDown, __ErrorEvent -} ; - -/*! - :INIT state and its event specific elements - See the spec in http://wikis.in.nokia.com/Runtimes/NewGestureLibrary - Down is only valid event in :INIT state - The event is consumed immediately, so that the state machine will process only these - methods when processing the message. - If touch timer has been set, the next state is InTouchTime. - If no touch timer, but if hold timer has been defined, the next state is InHoldTime_U - If no touch or hold timer have been defined, but touch area has been defined, next state is InTouchArea. - 11-May-2009: addition: add another touch area: one for touch time and one for touch area after touch time - has elapsed. This allows "sloppy" touch to be handled properly without extra move if touchtimearea is larger, - but after touch has been detected a smaller movement is allowed. - */ -const STATE_ELEMENT Init__Down[12] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(SetGestureStart), Eignore, - 0, ACT(SetCurrentPos), Eignore, - CND(IsTouchTimer), ACT(InitTouchTimer), Eignore, - CND(IsHoldTimer), ACT(InitHoldTimer), Eignore, - CND(IsTouchTimeArea), ACT(PrepareTouchTimeArea),Eignore, - CND(IsHoldArea), ACT(PrepareHoldArea) ,Eignore, - CND(IsTouchTimer), 0, EInTouchTime, - 0, ACT(ProduceTouch), Eignore, - CND(IsHoldTimer), 0, EInHoldTime_U, - CND(IsTouchArea), ACT(PrepareTouchArea),EInTouchArea, - 0, 0, EDispatch // If nothing else happens, goto to Dispatch state -}; -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the Init state - */ -const STATE_ELEMENT Init__ErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInit -}; - -/*! - * :INIT - * note that only valid event is DOWN, all the rest can be handled as errors - */ -const STATE Init__[7] = { - EDown, Init__Down, - EDrag, Init__ErrorEvent, - ECapacitiveUP, Init__ErrorEvent, - EResistiveUP, Init__ErrorEvent, - ETouchTimer, Init__ErrorEvent, - EHoldTimer, Init__ErrorEvent, - ESuppressTimer, Init__ErrorEvent -}; - -/*! - * :Dispatch state end its elements - * Here the valid events are DRAG and the UP events. - */ -const STATE_ELEMENT Dispatch__Drag[7] = { - 0, ACT(StoreMovePos), Eignore, - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(SetCurrentPos), Eignore, - 0, ACT(AddDraggingPos), Eignore, - 0, ACT(ProduceMove), Eignore, - CND(LooksLikeHold), ACT(InitHoldTimer),EInHoldTime_U, - 0, 0, EDispatch -} ; - -const STATE_ELEMENT Dispatch__CapacitiveUp[3] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(SetCurrentPos), Eignore, - 0, ACT(ProduceRelease), EInit -} ; - -const STATE_ELEMENT Dispatch__ResistiveUp[4] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(SetCurrentPos), Eignore, - CND(IsSuppressTimer),ACT(InitMoveSuppressTimer), ESuppress_D, - 0, ACT(ProduceRelease), EInit -} ; - -/*! - * All the rest of the events are errors so produce error entry to log and - * stay in the Dispatch state - * (TODO: note that in the future we may further - * define the error cases so that they may change state; ) - */ -const STATE_ELEMENT DispatchErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EDispatch -}; - -const STATE Dispatch__[7] = { - EDown, DispatchErrorEvent, - EDrag, Dispatch__Drag, - ECapacitiveUP, Dispatch__CapacitiveUp, - EResistiveUP, Dispatch__ResistiveUp, - ETouchTimer, DispatchErrorEvent, - EHoldTimer, DispatchErrorEvent, - ESuppressTimer, DispatchErrorEvent -}; - -/*! - * :InTouchTime state end its elements - * Here the valid events are DRAG and the UP events and the TouchTimer - */ -const STATE_ELEMENT InTouchTime__Drag[6] = { - 0, ACT(StoreMovePos), Eignore, - CND(InsideTouchTimeArea), ACT(ConsumeEvent), Eignore, - CND(InsideTouchTimeArea), ACT(AddToTouch), EInTouchTime, // Calculate touch XY as average of the touches - 0, ACT(ClearTouchTimer), Eignore, // These lines are done only if InsideTouchArea returns false - 0, ACT(ClearHoldTimer), Eignore, - 0, ACT(ProduceTouch), EDispatch - -} ; -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch - */ -const STATE_ELEMENT InTouchTime__CapacitiveUp[4] = { - 0, ACT(SetCurrentPos), Eignore, - 0, ACT(ClearTouchTimer), Eignore, - 0, ACT(ClearHoldTimer), Eignore, - 0, ACT(ProduceTouch), EDispatch -} ; -/** - * Note that ConsumeEvent is not called if IsHoldTimer returns false, so the Dispatch will be done - * by the state machine. - */ -const STATE_ELEMENT InTouchTime__ResistiveUp[5] = { - 0, ACT(SetCurrentPos), Eignore, - 0, ACT(ClearTouchTimer), Eignore, - 0, ACT(ProduceTouch), Eignore, - CND(IsHoldTimer), 0, /*ACT(ConsumeEvent),*/EInHoldTime_U, // Note that otherwise immediate UP is handled improperly - 0, 0, EDispatch -} ; - -const STATE_ELEMENT InTouchTime__TouchTimer[6] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(ClearTouchTimer), Eignore, - 0, ACT(ProduceTouch), Eignore, - CND(IsTouchArea), ACT(PrepareTouchArea),Eignore, // prepare the other touch area - CND(IsHoldTimer), 0, EInHoldTime_U, - 0, 0, EInTouchArea -} ; - - -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the InTouchTime state - */ -const STATE_ELEMENT InTouchTimeErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInTouchTime -}; - -const STATE InTouchTime__[7] = { - EDown, InTouchTimeErrorEvent, - EDrag, InTouchTime__Drag, - ECapacitiveUP, InTouchTime__CapacitiveUp, - EResistiveUP, InTouchTime__ResistiveUp, - ETouchTimer, InTouchTime__TouchTimer, - EHoldTimer, InTouchTimeErrorEvent, - ESuppressTimer, InTouchTimeErrorEvent -}; - -/*! - * :InHoldTime_U state end its elements - * Here only touch timer event is invalid - */ - -const STATE_ELEMENT InHoldTime_U__Down[1] = { - 0, 0, EInHoldTime_D // Note that ConsumeEvent is not called -} ; - -const STATE_ELEMENT InHoldTime_U__Drag[3] = { - 0, ACT(StoreMovePos), Eignore, - CND(InsideHoldArea), ACT(ConsumeEvent), EInHoldTime_U, - 0, ACT(ClearHoldTimer), EDispatch // Note that in this case ConsumeEvent is not called -} ; -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch - */ -const STATE_ELEMENT InHoldTime_U__CapacitiveUp[1] = { - 0, ACT(ClearHoldTimer), EDispatch // Note that ConsumeEvent not called -} ; -/** - * - */ -const STATE_ELEMENT InHoldTime_U__ResistiveUp[5] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(SetCurrentPos), Eignore, - CND(IsSuppressTimer),ACT(InitTouchSuppressTimer), EInHoldTime_D, // If suppression, start timer and wait for down or timer - 0, ACT(ClearHoldTimer), Eignore, // remember to do this - 0, ACT(ProduceRelease), EInit // No suppression, then this is immediate release -} ; - -const STATE_ELEMENT InHoldTime_U__HoldTimer[3] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(ProduceHold), Eignore, - 0, ACT(RestartHoldTimer), EInHoldTime_U, -} ; - -const STATE_ELEMENT InHoldTime_U__SuppressTimer[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInHoldTime_U -} ; - - -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the InHoldTime_U state - */ -const STATE_ELEMENT InHoldTime_UErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInHoldTime_U -}; - -const STATE InHoldTime_U__[7] = { - EDown, InHoldTime_U__Down, - EDrag, InHoldTime_U__Drag, - ECapacitiveUP, InHoldTime_U__CapacitiveUp, - EResistiveUP, InHoldTime_U__ResistiveUp, - ETouchTimer, InHoldTime_UErrorEvent, - EHoldTimer, InHoldTime_U__HoldTimer, - ESuppressTimer, InHoldTime_U__SuppressTimer -}; - - -/*! - * :InHoldTime_D state end its elements - * Here drag, touch timer and suppress timer events are invalid - */ - -const STATE_ELEMENT InHoldTime_D__Down[5] = { - 0, ACT(ClearSuppressTimer), Eignore, - 0, ACT(ConsumeEvent), Eignore, - CND(InsideHoldArea), 0, EInHoldTime_U, - 0, ACT(ClearHoldTimer), Eignore, - 0, ACT(ProduceMove), EDispatch -} ; - -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U - */ -const STATE_ELEMENT InHoldTime_D__CapacitiveUp[1] = { - 0, 0, EInHoldTime_U -} ; -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U - */ -const STATE_ELEMENT InHoldTime_D__ResistiveUp[1] = { - 0, 0, EInHoldTime_U // InHoldTime_U initialises timers etc. if needed -} ; -/*! - * In case of hold timer has been elapsed stop the timers, generate Release UI event. - */ -const STATE_ELEMENT InHoldTime_D__HoldTimer[4] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(ClearSuppressTimer), Eignore, - 0, ACT(ClearHoldTimer), Eignore, - 0, ACT(ProduceRelease), EInit, -} ; -/*! - * If suppress timer hits, stop the timers and generate Release UI event. - */ -const STATE_ELEMENT InHoldTime_D__SuppressTimer[4] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(ClearSuppressTimer), Eignore, - 0, ACT(ClearHoldTimer), Eignore, - 0, ACT(ProduceRelease), EInit, -} ; - -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the InHoldTime_D state - */ -const STATE_ELEMENT InHoldTime_DErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInHoldTime_D -}; - -const STATE InHoldTime_D__[7] = { - EDown, InHoldTime_D__Down, - EDrag, InHoldTime_DErrorEvent, - ECapacitiveUP, InHoldTime_D__CapacitiveUp, - EResistiveUP, InHoldTime_D__ResistiveUp, - ETouchTimer, InHoldTime_DErrorEvent, - EHoldTimer, InHoldTime_D__HoldTimer, - ESuppressTimer, InHoldTime_D__SuppressTimer -}; - - -/*! - * :InTouchArea state end its elements - * Here Drag and Up events are valid. - * If drag is inside touch are it is ignored, otherwise - * the Dispatch state will handle the event. - */ - -const STATE_ELEMENT InTouchArea__Drag[3] = { - 0, ACT(StoreMovePos), Eignore, - CND(InsideTouchArea), ACT(ConsumeEvent), EInTouchArea, - 0, 0, EDispatch // Note that in this case ConsumeEvent has not been called so Dispatch state processes the message -} ; - -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch - */ -const STATE_ELEMENT InTouchArea__CapacitiveUp[1] = { - 0, 0, EDispatch -} ; -/** - * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch - */ -const STATE_ELEMENT InTouchArea__ResistiveUp[1] = { - 0, 0, EDispatch -} ; - -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the InTouchArea state - */ -const STATE_ELEMENT InTouchAreaErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), EInTouchArea -}; - -const STATE InTouchArea__[7] = { - EDown, InTouchAreaErrorEvent, - EDrag, InTouchArea__Drag, - ECapacitiveUP, InTouchArea__CapacitiveUp, - EResistiveUP, InTouchArea__ResistiveUp, - ETouchTimer, InTouchAreaErrorEvent, - EHoldTimer, InTouchAreaErrorEvent, - ESuppressTimer, InTouchAreaErrorEvent -}; - - -/*! - * :Suppress_D state end its elements - * Here Down and suppress timers are OK. - */ - -/*! - * Down will be handled as a Drag event in the Dispatch state. - */ -const STATE_ELEMENT Suppress_D__Down[4] = { - 0, ACT(ClearSuppressTimer), Eignore, - 0, ACT(RenameToDrag), EDispatch -} ; -/*! - * Suppress timer will generate Release UI event. - */ -const STATE_ELEMENT Suppress_D__SuppressTimer[3] = { - 0, ACT(ConsumeEvent), Eignore, - 0, ACT(ClearSuppressTimer), Eignore, - 0, ACT(ProduceRelease), EInit, -} ; - -/** - * All the rest of the events are errors so produce error entry to log and - * stay in the Suppress_D state - */ -const STATE_ELEMENT Suppress_DErrorEvent[2] = { - 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... - 0, ACT(ErrorEvent), ESuppress_D -}; - -const STATE Suppress_D__[7] = { - EDown, Suppress_D__Down, - EDrag, Suppress_DErrorEvent, - ECapacitiveUP, Suppress_DErrorEvent, - EResistiveUP, Suppress_DErrorEvent, - ETouchTimer, Suppress_DErrorEvent, - EHoldTimer, Suppress_DErrorEvent, - ESuppressTimer, Suppress_D__SuppressTimer -}; -/*! - * The allStates array contains all the possible states of the state machine. - */ -const STATE* const allStates[8] = -{ - Ignore__, - Init__, - Dispatch__, - InTouchTime__, - InHoldTime_U__, - InHoldTime_D__, - InTouchArea__, - Suppress_D__ -}; -/*! - * stateNames are used in the logging - */ -const char* const stateNames[8] = -{ - "Ignore", - "Init", - "Dispatch", - "InTouchTime", - "InHoldTime_U", - "InHoldTime_D", - "InTouchArea", - "Suppress" -}; - -// event names are also used in logging -const char* const hweventNames[] = { - "EDown", - "EDrag", - "ECapacitiveUP", - "EResistiveUP", - "ETouchTimer", - "EHoldTimer", - "ESuppressTimer" -} ; - -/*! CStateEngine contains the methods used in the state machine implementation. - * - * The methods in CStateEngine used in the state machine definition are - * either condition methods or action methods. - * - * Constructor - * \param[in]: MTimerInterface atimerif. An attempt to make this more OS agnostic the actual - * timers are accessed using a separate interface. - */ -CStateEngine::CStateEngine(CStateEngineConfiguration* aConfig, MTimerInterface* atimerif, int aIndex) -{ - m_config = aConfig ; - m_timerif = atimerif ; - m_currentState = EInit ; - m_index = aIndex ; -} - -CStateEngine::~CStateEngine() -{ - // Just to be sure... - iTouchPoints.Reset() ; - iDragPoints.ResetAndDestroy() ; -} -/*! - * ConsumeEvent: the method defines that the turnStateMachine will stop the processing - * of the state methods after it has reached the next state. - * - */ -void CStateEngine::ConsumeEvent() -{ - m_eventConsumed = true ; -} -/*! - * Condition method - * \return true, if the touch timer limit > 0 - */ -bool CStateEngine::IsTouchTimer() -{ - bool isit = (m_config->m_touchTimerLimit > 0) ; - - return isit ; -} -/*! - * Condition method - * \return true, if the hold timer limit > 0 - */ -bool CStateEngine::IsHoldTimer() -{ - bool isit = (m_config->m_holdTimerLimit > 0) ; - - return isit ; -} -/*! - * Condition method - * \return true, if the suppress timer limit > 0 - */ -bool CStateEngine::IsSuppressTimer() -{ - bool isit = (m_config->m_suppressTimerLimit > 0) ; - - return isit ; -} -/*! - * Condition method - * \return true, if the touch area has been defined (the touch tolerancelength > 0) - */ -bool CStateEngine::IsTouchTimeArea() -{ - bool isit = (m_config->m_touchTimeTolerance.iX > 0) ; - return isit ; -} -/*! - * Condition method - * \return true, if the touch area has been defined (the touch tolerancelength > 0) - */ -bool CStateEngine::IsTouchArea() -{ - bool isit = (m_config->m_touchTolerance.iX > 0) ; - return isit ; -} -/*! - * Condition method - * \return true, if the hold area has been defined (the hold tolerancelength > 0) - */ -bool CStateEngine::IsHoldArea() -{ - bool isit = (m_config->m_holdTolerance.iX > 0) ; - return isit ; -} - -bool CStateEngine::InsideArea(const TPoint& point, - const TRect& rect, - TAreaShape shape, - const TPoint& tolerance) -{ - bool isit; - switch(shape) - { - default: // pass trough - case ERectangle: - { - isit = rect.Contains(m_hwe.iPosition) ; - break ; - } - case ECircle: - { - TPoint delta = m_hwe.iPosition - point; - long circlepoint = delta.iX * delta.iX + delta.iY * delta.iY; - isit = (circlepoint < tolerance.iX * tolerance.iX); - break ; - } - case EEllipse: - { - int asquare = tolerance.iX * tolerance.iX ; - int bsquare = tolerance.iY * tolerance.iY ; - TPoint delta = m_hwe.iPosition - point; - int result = (delta.iX * delta.iX) * bsquare + (delta.iY * delta.iY) * asquare; - - isit = (result < asquare * bsquare); - break ; - } - } - return isit ; -} - -/*! - * Condition method - * Check if the current event is positioned inside the touch area. - * Touch area can be a rectangle, a circle or an ellipse, so different - * calculation needs to be done based on the shape of the area. - */ -bool CStateEngine::InsideTouchTimeArea() -{ - return InsideArea(m_touchCentre, m_touchRect, - m_config->m_touchAreaShape, m_config->m_touchTimeTolerance); -} -/*! - * Condition method - * Check if the current event is positioned inside the touch area. - * Touch area can be a rectangle, a circle or an ellipse, so different - * calculation needs to be done based on the shape of the area. - */ -bool CStateEngine::InsideTouchArea() -{ - return InsideArea(m_touchCentre, m_touchRect, - m_config->m_touchAreaShape, m_config->m_touchTolerance); -} -/*! - * Condition method - * Check if the current event is positioned inside the hold area. - * Hold area can be a rectangle, a circle or an ellipse, so different - * calculation needs to be done based on the shape of the area. - */ -bool CStateEngine::InsideHoldArea() -{ - return InsideArea(m_holdCentre, m_holdRect, - m_config->m_holdAreaShape, m_config->m_holdTolerance); -} -/*! - * Condition method - * Check if the gesture looks like a hold, i.e. the movement has stopped. - * \sa isNewHoldingPoint - */ -bool CStateEngine::LooksLikeHold() -{ - bool isit = isNewHoldingPoint() ; - return isit ; -} -/*! - * Action method - * Error logging. - */ -void CStateEngine::ErrorEvent() -{ - // Log the error - if (m_config->m_enableLogging) - { - LOGARG("ErrorEvent: %s %s", stateNames[m_currentState], hweventNames[m_hwe.iType]) ; - } -} -/*! - * Action method - * Initialize touch timer. At the same time calculate also the touch rectangle. - */ -void CStateEngine::InitTouchTimer() -{ - m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ; - m_touchCentre = m_hwe.iPosition ; - m_timerif->startTouchTimer(m_config->m_touchTimerLimit, m_index) ; -} -/*! - * Action method. - * Initialize hold timer. At the same time calculate also the hold rectangle. - */ -void CStateEngine::InitHoldTimer() -{ - m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ; - m_holdCentre = m_hwe.iPosition ; - m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ; -} -/*! - * Action method - * Restart the hold timer using the hold timer limit. - */ -void CStateEngine::RestartHoldTimer() -{ - m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ; -} -/*! - * Action method - * Initialize suppression timer. This timer is used during touch detection when - * resistive UP has been detected. If new DOWN comes while timer is running, it is ignored. - */ -void CStateEngine::InitTouchSuppressTimer() -{ - m_timerif->startSuppressTimer(m_config->m_suppressTimerLimit, m_index) ; -} -/*! - * Action method. - * Initialize suppression timer after move. Tests show that when user is using light touch and - * moving finger to opposite directions there may be accidental ups and downs where the time between - * up and down may be well over 120 ms. - */ -void CStateEngine::InitMoveSuppressTimer() -{ - m_timerif->startSuppressTimer(m_config->m_moveSuppressTimerLimit, m_index) ; -} -/*! - * Action method - * Stop the touch timer. - */ -void CStateEngine::ClearTouchTimer() -{ - m_timerif->cancelTouchTimer(m_index) ; -} -/*! - * Action method - * Stop the hold timer. - */ -void CStateEngine::ClearHoldTimer() -{ - m_timerif->cancelHoldTimer(m_index) ; -} -/*! - * Action method - * Stop the suppress timer. - */ -void CStateEngine::ClearSuppressTimer() -{ - m_timerif->cancelSuppressTimer(m_index) ; -} -/*!Helper method. - * Create UI event - * \param code The new UI event type (Touch, Release, Move, Hold) - */ -CUiEvent* CStateEngine::createUIEventL(TUiEventCode code, const TPoint& aPos) -{ - - m_previousUiGenerated = code ; - return CUiEvent::NewL(code, m_gestureStartXY, aPos, getPreviousXY(aPos), - isTimerMessage(), m_hwe.iTarget, getInterval(), m_index, m_hwe.iTime.Int64()) ; -} -/*! - * Return the previous XY position and store the current for next round - */ -TPoint CStateEngine::getPreviousXY(const TPoint& aCurrentXY) -{ - TPoint p = m_previousXY ; - m_previousXY = aCurrentXY ; - return p ; -} -/*! - * \return true, if the current event was timer triggered - */ -bool CStateEngine::isTimerMessage() -{ - return (m_hwe.iType >= ETouchTimer); // NOTE: if new events are added at the end of the list this needs to be changed -} -/*! - * Action method. - * Generate the Touch UI event. - * If there are a set of touch points collected, calculate the position to the - * Touch UI event to be the average of the collected points. - */ -void CStateEngine::ProduceTouch() -{ - m_wasFiltered = false ; - CUiEvent* cue = NULL; - getInterval() ; // dummy call to initialize the variable.... - TInt err(KErrNone); - if (iTouchPoints.Count()>0) - { - // calculate average of the touch points - m_currentTouchXY = calculateTouchAverageFromPoints() ; - TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_currentTouchXY)) ; - } - else - { - TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_uiEventXY)) ; - } - if(!err) - m_config->m_uiEventSender->AddEvent(cue) ; -} -/*! - * Action method - * Generate the Move UI event. The position of the event has been set in the SetCurrentPos - * The previous position needs some special handling, if filtering has been used. - * \sa SetCurrentPos - */ -void CStateEngine::ProduceMove() -{ - m_wasFiltered = false ; - if (m_uiEventXY == m_previousXY) { - return; - } - CUiEvent* cue = NULL; - TRAPD(err, cue = createUIEventL(stmUiEventEngine::EMove, m_uiEventXY)) ; - - if(!err) - m_config->m_uiEventSender->AddEvent(cue) ; -} -/*! - * Action method - * Generate the Release UI event. - */ -void CStateEngine::ProduceRelease() -{ - m_wasFiltered = false ; - CUiEvent* cue = NULL; - TRAPD(err, cue = createUIEventL(stmUiEventEngine::ERelease, m_uiEventXY)) ; - if(!err) - m_config->m_uiEventSender->AddEvent(cue) ; - - if (m_config->m_enableLogging) - { - LOGFLUSH ; - } -} -/*! - * Action method - * Generate the Hold UI event. - */ -void CStateEngine::ProduceHold() -{ - m_wasFiltered = false ; - CUiEvent* cue = NULL; - TRAPD(err, cue = createUIEventL(stmUiEventEngine::EHold, m_holdCentre)) ; - if(!err) - m_config->m_uiEventSender->AddEvent(cue) ; - -} -/*! - * Action method - * Rename the current event to drag. This is used when the accidental up/down message pair - * has been detected, the DOWN event is handled as it were a move event. - */ -void CStateEngine::RenameToDrag() -{ - m_hwe.iType = stmUiEventEngine::EDrag ; -} -/*! - * Action method - * Initialize the touch time area. Clear the array for collected touch points and - * calculate the touch rectangle. - */ -void CStateEngine::PrepareTouchTimeArea() -{ - if (iTouchPoints.Count()>0) iTouchPoints.Reset() ; - m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTimeTolerance) ; -} - -/*! - * Action method - * Initialize the touch area. Clear the array for collected touch points and - * calculate the touch rectangle. - */ -void CStateEngine::PrepareTouchArea() -{ - if (iTouchPoints.Count()>0) iTouchPoints.Reset() ; - m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ; -} -/*! - * Action method - * Initialize the hold area rectangle. - */ -void CStateEngine::PrepareHoldArea() -{ - m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ; -} -/*! - * Action method - * Store the current position and time always when we see EDrag. The stored value is used - * to calculate correct speed after filtered messages. - */ -void CStateEngine::StoreMovePos() -{ - if (m_config->m_enableLogging) - { - LOGARG("store move pos from (%d, %d) to (%d, %d)", - m_lastFilteredPosition.iX, m_lastFilteredPosition.iY,m_hwe.iPosition.iX, - m_hwe.iPosition.iY ) ; - } - m_lastFilteredPosition = m_hwe.iPosition ; - m_lastFilteredMessageTime = m_hwe.iTime ; - -} -/*! - * Action method - * Store the current position and time. - */ -void CStateEngine::SetCurrentPos() -{ - m_uiEventXY = m_hwe.iPosition ; -} -/*! - * Action method - * Initialize the gesture starting. - */ -void CStateEngine::SetGestureStart() -{ - m_gestureStartXY = m_hwe.iPosition ; - m_previousXY = m_hwe.iPosition ; - m_gestureTarget = m_hwe.iTarget ; - iDragPoints.ResetAndDestroy() ; - iTouchPoints.Reset() ; -} -/*! - * Action method - * Add current point to the set of touch points. - */ -void CStateEngine::AddToTouch() -{ - iTouchPoints.Append(THwEvent(m_hwe.iType, - m_hwe.iPosition, - m_hwe.iTime, - m_hwe.iTarget, - m_index) - ) ; - // calculate the average of touch points and move the touch area accordingly - // this allows slight movement of the figertip while inside touch time - if (iTouchPoints.Count()>2) - { - TPoint newtp = calculateTouchAverageFromPoints() ; - m_touchRect = ToleranceRect(newtp, m_config->m_touchTolerance) ; - m_holdRect = ToleranceRect(newtp, m_config->m_holdTolerance) ; - } -} -/*! - * Action method - * Add the current point to the set of dragging points. - * The set of dragging points is examined to determine if a enw hold has been started. - */ -void CStateEngine::AddDraggingPos() -{ - iDragPoints.Append(new THwEvent(m_hwe.iType, - m_hwe.iPosition, - m_hwe.iTime, - m_hwe.iTarget, - m_index) - ) ; -} -/*! - * HandleStateEvent processes one event, which can be either pointer event or timer event. - * The event is handled by calling the turnStateMachine method. - */ -bool CStateEngine::handleStateEvent() -{ - // We get an event into m_hwe by this moment, lets kick the state machine - m_wasFiltered = ETrue ; - - CalculateDelta() ; - turnStateMachine() ; - - m_previousPointerEventPosition = m_hwe.iPosition ; - return m_wasFiltered ; -} - -/*! - * Get the current touch rectangle. If touch state not currently on, returns TRect(TPoint(0,0),TPoint(0,0)) - * (touch state meaning that the touch timer is still running and the points have been kept inside the area) - */ -TRect CStateEngine::getTouchArea() -{ - return m_touchRect ; -} -/*! - * get the hold area rectangle - */ -TRect CStateEngine::getHoldArea() -{ - return m_holdRect ; -} -/*! - * MStateMachine method. - */ -bool CStateEngine::wasLastMessageFiltered() -{ - return m_wasFiltered ; -} - -/*! - * Check if the last X points in the stored points look like the movement has stopped - */ -bool CStateEngine::isNewHoldingPoint() -{ - int x = iDragPoints.Count(); - if (x > 2) // are there any points to be checked? - { - THwEvent* phwe = iDragPoints[x-1] ; - THwEvent* phweinsidehold = phwe ; - TRect recth = ToleranceRect(phwe->iPosition, m_config->m_holdTolerance) ; - // Look backwards from the last point to see if there are enought points (enough in time) to look like a hold - x -= 2 ; - while (x > 0 && recth.Contains(iDragPoints[x]->iPosition)) - { - phweinsidehold = iDragPoints[x]; - --x; - } - TTimeIntervalMicroSeconds tival = phwe->iTime.MicroSecondsFrom(phweinsidehold->iTime) ; - - /** - * remove the extra points from the list if they are outside of holding area - */ - while (x > 0) - { - THwEvent* p = iDragPoints[x] ; - delete p ; - iDragPoints.Remove(x) ; - --x ; - } - - // See the time difference of the two points which still are inside the hold area - TTimeIntervalMicroSeconds limit = m_config->m_holdTimerLimit/2 ; - if (tival > limit) - { - if (m_config->m_enableLogging) - { - LOGARG("isNewHoldingPoint: %s, dragpoints count %d", - stateNames[m_currentState], iDragPoints.Count()) ; - } - return true ; - } - } - else - { - // one or 0 points does not look like hold - - } - return false ; -} -/*! - * calculate simple average of the touch points, i.e. calculate the average of the previous and current - * position. Note that the touch point remains the same, this just calculates new value for the UI position - */ -void CStateEngine::CalculateTouchAverage() -{ - m_uiEventXY.iX = (m_uiEventXY.iX+m_hwe.iPosition.iX)/2 ; - m_uiEventXY.iY = (m_uiEventXY.iY+m_hwe.iPosition.iY)/2 ; -} -/*! - * Calculate the movement vector. - */ -void CStateEngine::CalculateDelta() -{ - m_deltaVector.iX = m_hwe.iPosition.iX-m_previousPointerEventPosition.iX ; - m_deltaVector.iY = m_hwe.iPosition.iY-m_previousPointerEventPosition.iY ; -} -/*!internal - * Debug logging method - */ -void CStateEngine::DebugPrintState(TStateMachineState anextstate) -{ - if (m_config->m_enableLogging) - { - LOGARG("%s: cuiev(%d,%d) cTxy ((%d,%d)(%d,%d)) cHxy ((%d,%d)(%d,%d)) gsXY(%d,%d) dV(%d,%d) EVNT(%d,%d (%s)) going to %s", - stateNames[m_currentState], - m_uiEventXY.iX, m_uiEventXY.iY, - m_touchRect.iTl.iX, m_touchRect.iTl.iY,m_touchRect.iBr.iX, m_touchRect.iBr.iY, - m_holdRect.iTl.iX, m_holdRect.iTl.iY,m_holdRect.iBr.iX, m_holdRect.iBr.iY, - m_gestureStartXY.iX, m_gestureStartXY.iY, - m_deltaVector.iX, m_deltaVector.iY, - m_hwe.iPosition.iX, m_hwe.iPosition.iY, hweventNames[m_hwe.iType], - stateNames[anextstate] - ); - } -} - -/*! - * calculate the rectangle for touch or hold - */ -TRect CStateEngine::ToleranceRect(const TPoint& aCenterPoint, const TPoint& tolerance) -{ - // grow by the tolerance length, while keeping the center point - TRect toleranceRect( - aCenterPoint - tolerance, - aCenterPoint + tolerance); - return toleranceRect; -} -/*! - * turnStateMachine. Go trough the state elements found for the current event - * until the event has been consumed. - * - * \pre m_currentState defines the current state and the index to the allStates array. - * \pre m_hwe is the message being handled. The corresponding STATE_ELEMENT array must be found and processed. - * - */ -void CStateEngine::turnStateMachine() -{ - - const STATE_ELEMENT* pelement ; - m_eventConsumed = false ; // run the loop until the event has been consumed - // Now run trough the motions of the state elements, and prepare to change to next state while doing so. - // If the state elements set the m_eventConsumed then all is done - while (!m_eventConsumed) - { - int i = 0 ; - const STATE* const pcurrentstate = allStates[m_currentState] ; - // Since each state definition must contain entries for all possible events the following loop cannot fail ;-) - while (pcurrentstate[i].theEvent != m_hwe.iType ) ++i ; - pelement = pcurrentstate[i].stateElements ; - TStateMachineState nextState = Eignore ; - /* - * Handle the individual state elements. If there is a condition function, - * call the function and if it returns true, handle the action function and possible next state - * if the condition returns false, continue to next element - * if there is no condition, run the action function if it exists. - * if the next state is defined (i.e it is != Eignore), go to that state - */ - while (nextState == Eignore) - { - condition_t cndfunc = pelement->conditionFunction ; - action_t actfunc = pelement->actionFunction ; - if (cndfunc != 0) - { - /* - * There was a condition function, call it to see whether the action needs to performed and/or the next satte defined - */ - if (cndfunc(this)) - { - // Condition was true, handle it - // call the action if it exists - if (actfunc != 0) actfunc(this) ; - // and now get to the next state - nextState = pelement->nextState ; // Note that while this remains Eignore there are elements to be run - } - } - else - { - /** - * No condition function, call the possible action function and get the next state - */ - if (actfunc != 0) actfunc(this) ; - nextState = pelement->nextState ; // Note that while this remains Eignore there are elements to be run - } - ++pelement ; // next entry in the elements - } - if (m_config->m_enableLogging) DebugPrintState(nextState) ; - m_currentState = nextState ; // Change to the next state - } -} -TTimeIntervalMicroSeconds CStateEngine::getInterval() -{ - TTime now ; - now.HomeTime() ; - TTimeIntervalMicroSeconds interval = now.MicroSecondsFrom(m_lastMessageTime) ; - m_lastMessageTime = now ; - return interval ; -} - -TPoint CStateEngine::calculateTouchAverageFromPoints() -{ - TPoint tp ; - int count = iTouchPoints.Count() ; - for (int i = 0; i < count; i++) - { - tp += iTouchPoints[i].iPosition; - } - if(count) - { - tp.iX /= count ; - tp.iY /= count ; - } - return tp ; -} -