|
1 /* |
|
2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include "stateengine.h" |
|
20 #include "utils.h" |
|
21 #include "uievent.h" |
|
22 #include "uieventsender.h" |
|
23 #include "filelogger.h" |
|
24 //#include "flogger.h" |
|
25 |
|
26 using namespace stmUiEventEngine ; |
|
27 |
|
28 /*! |
|
29 State definitions glue together the methods of the stateengine.cpp |
|
30 so that it will behave as defined in the state machine specification. |
|
31 First define the separate elements for each possible event and then tie them together |
|
32 to create one state entry. The state entries then are put to array |
|
33 where the index is at the same time also the state ID. |
|
34 |
|
35 STATE_ELEMENT arrays define the methods called when handling a message. |
|
36 \sa STATE_ELEMENT. |
|
37 Note that the last row of STATE_ELEMENT array must NOT have a ConditionFunction entry |
|
38 and it must have a NextState entry != Eignore. Otherwise the state machine will |
|
39 not behave correctly. |
|
40 |
|
41 */ |
|
42 /*! Add macro with token pasting to make creation of the state machine tables easier |
|
43 and removing the necessity to write the classname twice. |
|
44 Maybe there would be some better way to do this using templates and typedefs? |
|
45 */ |
|
46 #define CND(x) isF<CStateEngine,&CStateEngine::##x> |
|
47 #define ACT(x) aF<CStateEngine,&CStateEngine::##x> |
|
48 |
|
49 /********************************************************************************* |
|
50 * empty statedef as a dummy entry |
|
51 * */ |
|
52 const STATE_ELEMENT __ErrorEvent[1] = { |
|
53 0, |
|
54 ACT(ErrorEvent), |
|
55 EInit |
|
56 }; |
|
57 |
|
58 const STATE Ignore__[1] = { |
|
59 EDown, __ErrorEvent |
|
60 } ; |
|
61 |
|
62 /*! |
|
63 :INIT state and its event specific elements |
|
64 See the spec in http://wikis.in.nokia.com/Runtimes/NewGestureLibrary |
|
65 Down is only valid event in :INIT state |
|
66 The event is consumed immediately, so that the state machine will process only these |
|
67 methods when processing the message. |
|
68 If touch timer has been set, the next state is InTouchTime. |
|
69 If no touch timer, but if hold timer has been defined, the next state is InHoldTime_U |
|
70 If no touch or hold timer have been defined, but touch area has been defined, next state is InTouchArea. |
|
71 11-May-2009: addition: add another touch area: one for touch time and one for touch area after touch time |
|
72 has elapsed. This allows "sloppy" touch to be handled properly without extra move if touchtimearea is larger, |
|
73 but after touch has been detected a smaller movement is allowed. |
|
74 */ |
|
75 const STATE_ELEMENT Init__Down[12] = { |
|
76 0, ACT(ConsumeEvent), Eignore, |
|
77 0, ACT(SetGestureStart), Eignore, |
|
78 0, ACT(SetCurrentPos), Eignore, |
|
79 CND(IsTouchTimer), ACT(InitTouchTimer), Eignore, |
|
80 CND(IsHoldTimer), ACT(InitHoldTimer), Eignore, |
|
81 CND(IsTouchTimeArea), ACT(PrepareTouchTimeArea),Eignore, |
|
82 CND(IsHoldArea), ACT(PrepareHoldArea) ,Eignore, |
|
83 CND(IsTouchTimer), 0, EInTouchTime, |
|
84 0, ACT(ProduceTouch), Eignore, |
|
85 CND(IsHoldTimer), 0, EInHoldTime_U, |
|
86 CND(IsTouchArea), ACT(PrepareTouchArea),EInTouchArea, |
|
87 0, 0, EDispatch // If nothing else happens, goto to Dispatch state |
|
88 }; |
|
89 /** |
|
90 * All the rest of the events are errors so produce error entry to log and |
|
91 * stay in the Init state |
|
92 */ |
|
93 const STATE_ELEMENT Init__ErrorEvent[2] = { |
|
94 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
95 0, ACT(ErrorEvent), EInit |
|
96 }; |
|
97 |
|
98 /*! |
|
99 * :INIT |
|
100 * note that only valid event is DOWN, all the rest can be handled as errors |
|
101 */ |
|
102 const STATE Init__[7] = { |
|
103 EDown, Init__Down, |
|
104 EDrag, Init__ErrorEvent, |
|
105 ECapacitiveUP, Init__ErrorEvent, |
|
106 EResistiveUP, Init__ErrorEvent, |
|
107 ETouchTimer, Init__ErrorEvent, |
|
108 EHoldTimer, Init__ErrorEvent, |
|
109 ESuppressTimer, Init__ErrorEvent |
|
110 }; |
|
111 |
|
112 /*! |
|
113 * :Dispatch state end its elements |
|
114 * Here the valid events are DRAG and the UP events. |
|
115 */ |
|
116 const STATE_ELEMENT Dispatch__Drag[7] = { |
|
117 0, ACT(StoreMovePos), Eignore, |
|
118 0, ACT(ConsumeEvent), Eignore, |
|
119 0, ACT(SetCurrentPos), Eignore, |
|
120 0, ACT(AddDraggingPos), Eignore, |
|
121 0, ACT(ProduceMove), Eignore, |
|
122 CND(LooksLikeHold), ACT(InitHoldTimer),EInHoldTime_U, |
|
123 0, 0, EDispatch |
|
124 } ; |
|
125 |
|
126 const STATE_ELEMENT Dispatch__CapacitiveUp[3] = { |
|
127 0, ACT(ConsumeEvent), Eignore, |
|
128 0, ACT(SetCurrentPos), Eignore, |
|
129 0, ACT(ProduceRelease), EInit |
|
130 } ; |
|
131 |
|
132 const STATE_ELEMENT Dispatch__ResistiveUp[4] = { |
|
133 0, ACT(ConsumeEvent), Eignore, |
|
134 0, ACT(SetCurrentPos), Eignore, |
|
135 CND(IsSuppressTimer),ACT(InitMoveSuppressTimer), ESuppress_D, |
|
136 0, ACT(ProduceRelease), EInit |
|
137 } ; |
|
138 |
|
139 /*! |
|
140 * All the rest of the events are errors so produce error entry to log and |
|
141 * stay in the Dispatch state |
|
142 * (TODO: note that in the future we may further |
|
143 * define the error cases so that they may change state; ) |
|
144 */ |
|
145 const STATE_ELEMENT DispatchErrorEvent[2] = { |
|
146 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
147 0, ACT(ErrorEvent), EDispatch |
|
148 }; |
|
149 |
|
150 const STATE Dispatch__[7] = { |
|
151 EDown, DispatchErrorEvent, |
|
152 EDrag, Dispatch__Drag, |
|
153 ECapacitiveUP, Dispatch__CapacitiveUp, |
|
154 EResistiveUP, Dispatch__ResistiveUp, |
|
155 ETouchTimer, DispatchErrorEvent, |
|
156 EHoldTimer, DispatchErrorEvent, |
|
157 ESuppressTimer, DispatchErrorEvent |
|
158 }; |
|
159 |
|
160 /*! |
|
161 * :InTouchTime state end its elements |
|
162 * Here the valid events are DRAG and the UP events and the TouchTimer |
|
163 */ |
|
164 const STATE_ELEMENT InTouchTime__Drag[6] = { |
|
165 0, ACT(StoreMovePos), Eignore, |
|
166 CND(InsideTouchTimeArea), ACT(ConsumeEvent), Eignore, |
|
167 CND(InsideTouchTimeArea), ACT(AddToTouch), EInTouchTime, // Calculate touch XY as average of the touches |
|
168 0, ACT(ClearTouchTimer), Eignore, // These lines are done only if InsideTouchArea returns false |
|
169 0, ACT(ClearHoldTimer), Eignore, |
|
170 0, ACT(ProduceTouch), EDispatch |
|
171 |
|
172 } ; |
|
173 /** |
|
174 * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch |
|
175 */ |
|
176 const STATE_ELEMENT InTouchTime__CapacitiveUp[4] = { |
|
177 0, ACT(SetCurrentPos), Eignore, |
|
178 0, ACT(ClearTouchTimer), Eignore, |
|
179 0, ACT(ClearHoldTimer), Eignore, |
|
180 0, ACT(ProduceTouch), EDispatch |
|
181 } ; |
|
182 /** |
|
183 * Note that ConsumeEvent is not called if IsHoldTimer returns false, so the Dispatch will be done |
|
184 * by the state machine. |
|
185 */ |
|
186 const STATE_ELEMENT InTouchTime__ResistiveUp[5] = { |
|
187 0, ACT(SetCurrentPos), Eignore, |
|
188 0, ACT(ClearTouchTimer), Eignore, |
|
189 0, ACT(ProduceTouch), Eignore, |
|
190 CND(IsHoldTimer), 0, /*ACT(ConsumeEvent),*/EInHoldTime_U, // Note that otherwise immediate UP is handled improperly |
|
191 0, 0, EDispatch |
|
192 } ; |
|
193 |
|
194 const STATE_ELEMENT InTouchTime__TouchTimer[6] = { |
|
195 0, ACT(ConsumeEvent), Eignore, |
|
196 0, ACT(ClearTouchTimer), Eignore, |
|
197 0, ACT(ProduceTouch), Eignore, |
|
198 CND(IsTouchArea), ACT(PrepareTouchArea),Eignore, // prepare the other touch area |
|
199 CND(IsHoldTimer), 0, EInHoldTime_U, |
|
200 0, 0, EInTouchArea |
|
201 } ; |
|
202 |
|
203 |
|
204 /** |
|
205 * All the rest of the events are errors so produce error entry to log and |
|
206 * stay in the InTouchTime state |
|
207 */ |
|
208 const STATE_ELEMENT InTouchTimeErrorEvent[2] = { |
|
209 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
210 0, ACT(ErrorEvent), EInTouchTime |
|
211 }; |
|
212 |
|
213 const STATE InTouchTime__[7] = { |
|
214 EDown, InTouchTimeErrorEvent, |
|
215 EDrag, InTouchTime__Drag, |
|
216 ECapacitiveUP, InTouchTime__CapacitiveUp, |
|
217 EResistiveUP, InTouchTime__ResistiveUp, |
|
218 ETouchTimer, InTouchTime__TouchTimer, |
|
219 EHoldTimer, InTouchTimeErrorEvent, |
|
220 ESuppressTimer, InTouchTimeErrorEvent |
|
221 }; |
|
222 |
|
223 /*! |
|
224 * :InHoldTime_U state end its elements |
|
225 * Here only touch timer event is invalid |
|
226 */ |
|
227 |
|
228 const STATE_ELEMENT InHoldTime_U__Down[1] = { |
|
229 0, 0, EInHoldTime_D // Note that ConsumeEvent is not called |
|
230 } ; |
|
231 |
|
232 const STATE_ELEMENT InHoldTime_U__Drag[3] = { |
|
233 0, ACT(StoreMovePos), Eignore, |
|
234 CND(InsideHoldArea), ACT(ConsumeEvent), EInHoldTime_U, |
|
235 0, ACT(ClearHoldTimer), EDispatch // Note that in this case ConsumeEvent is not called |
|
236 } ; |
|
237 /** |
|
238 * Note that ConsumeEvent is missing so after doing this the state engine will do EDispatch |
|
239 */ |
|
240 const STATE_ELEMENT InHoldTime_U__CapacitiveUp[1] = { |
|
241 0, ACT(ClearHoldTimer), EDispatch // Note that ConsumeEvent not called |
|
242 } ; |
|
243 /** |
|
244 * |
|
245 */ |
|
246 const STATE_ELEMENT InHoldTime_U__ResistiveUp[5] = { |
|
247 0, ACT(ConsumeEvent), Eignore, |
|
248 0, ACT(SetCurrentPos), Eignore, |
|
249 CND(IsSuppressTimer),ACT(InitTouchSuppressTimer), EInHoldTime_D, // If suppression, start timer and wait for down or timer |
|
250 0, ACT(ClearHoldTimer), Eignore, // remember to do this |
|
251 0, ACT(ProduceRelease), EInit // No suppression, then this is immediate release |
|
252 } ; |
|
253 |
|
254 const STATE_ELEMENT InHoldTime_U__HoldTimer[3] = { |
|
255 0, ACT(ConsumeEvent), Eignore, |
|
256 0, ACT(ProduceHold), Eignore, |
|
257 0, ACT(RestartHoldTimer), EInHoldTime_U, |
|
258 } ; |
|
259 |
|
260 const STATE_ELEMENT InHoldTime_U__SuppressTimer[2] = { |
|
261 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
262 0, ACT(ErrorEvent), EInHoldTime_U |
|
263 } ; |
|
264 |
|
265 |
|
266 /** |
|
267 * All the rest of the events are errors so produce error entry to log and |
|
268 * stay in the InHoldTime_U state |
|
269 */ |
|
270 const STATE_ELEMENT InHoldTime_UErrorEvent[2] = { |
|
271 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
272 0, ACT(ErrorEvent), EInHoldTime_U |
|
273 }; |
|
274 |
|
275 const STATE InHoldTime_U__[7] = { |
|
276 EDown, InHoldTime_U__Down, |
|
277 EDrag, InHoldTime_U__Drag, |
|
278 ECapacitiveUP, InHoldTime_U__CapacitiveUp, |
|
279 EResistiveUP, InHoldTime_U__ResistiveUp, |
|
280 ETouchTimer, InHoldTime_UErrorEvent, |
|
281 EHoldTimer, InHoldTime_U__HoldTimer, |
|
282 ESuppressTimer, InHoldTime_U__SuppressTimer |
|
283 }; |
|
284 |
|
285 |
|
286 /*! |
|
287 * :InHoldTime_D state end its elements |
|
288 * Here drag, touch timer and suppress timer events are invalid |
|
289 */ |
|
290 |
|
291 const STATE_ELEMENT InHoldTime_D__Down[5] = { |
|
292 0, ACT(ClearSuppressTimer), Eignore, |
|
293 0, ACT(ConsumeEvent), Eignore, |
|
294 CND(InsideHoldArea), 0, EInHoldTime_U, |
|
295 0, ACT(ClearHoldTimer), Eignore, |
|
296 0, ACT(ProduceMove), EDispatch |
|
297 } ; |
|
298 |
|
299 /** |
|
300 * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U |
|
301 */ |
|
302 const STATE_ELEMENT InHoldTime_D__CapacitiveUp[1] = { |
|
303 0, 0, EInHoldTime_U |
|
304 } ; |
|
305 /** |
|
306 * Note that ConsumeEvent is missing so after doing this the state engine will do InHoldTime_U |
|
307 */ |
|
308 const STATE_ELEMENT InHoldTime_D__ResistiveUp[1] = { |
|
309 0, 0, EInHoldTime_U // InHoldTime_U initialises timers etc. if needed |
|
310 } ; |
|
311 /*! |
|
312 * In case of hold timer has been elapsed stop the timers, generate Release UI event. |
|
313 */ |
|
314 const STATE_ELEMENT InHoldTime_D__HoldTimer[4] = { |
|
315 0, ACT(ConsumeEvent), Eignore, |
|
316 0, ACT(ClearSuppressTimer), Eignore, |
|
317 0, ACT(ClearHoldTimer), Eignore, |
|
318 0, ACT(ProduceRelease), EInit, |
|
319 } ; |
|
320 /*! |
|
321 * If suppress timer hits, stop the timers and generate Release UI event. |
|
322 */ |
|
323 const STATE_ELEMENT InHoldTime_D__SuppressTimer[4] = { |
|
324 0, ACT(ConsumeEvent), Eignore, |
|
325 0, ACT(ClearSuppressTimer), Eignore, |
|
326 0, ACT(ClearHoldTimer), Eignore, |
|
327 0, ACT(ProduceRelease), EInit, |
|
328 } ; |
|
329 |
|
330 /** |
|
331 * All the rest of the events are errors so produce error entry to log and |
|
332 * stay in the InHoldTime_D state |
|
333 */ |
|
334 const STATE_ELEMENT InHoldTime_DErrorEvent[2] = { |
|
335 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
336 0, ACT(ErrorEvent), EInHoldTime_D |
|
337 }; |
|
338 |
|
339 const STATE InHoldTime_D__[7] = { |
|
340 EDown, InHoldTime_D__Down, |
|
341 EDrag, InHoldTime_DErrorEvent, |
|
342 ECapacitiveUP, InHoldTime_D__CapacitiveUp, |
|
343 EResistiveUP, InHoldTime_D__ResistiveUp, |
|
344 ETouchTimer, InHoldTime_DErrorEvent, |
|
345 EHoldTimer, InHoldTime_D__HoldTimer, |
|
346 ESuppressTimer, InHoldTime_D__SuppressTimer |
|
347 }; |
|
348 |
|
349 |
|
350 /*! |
|
351 * :InTouchArea state end its elements |
|
352 * Here Drag and Up events are valid. |
|
353 * If drag is inside touch are it is ignored, otherwise |
|
354 * the Dispatch state will handle the event. |
|
355 */ |
|
356 |
|
357 const STATE_ELEMENT InTouchArea__Drag[3] = { |
|
358 0, ACT(StoreMovePos), Eignore, |
|
359 CND(InsideTouchArea), ACT(ConsumeEvent), EInTouchArea, |
|
360 0, 0, EDispatch // Note that in this case ConsumeEvent has not been called so Dispatch state processes the message |
|
361 } ; |
|
362 |
|
363 /** |
|
364 * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch |
|
365 */ |
|
366 const STATE_ELEMENT InTouchArea__CapacitiveUp[1] = { |
|
367 0, 0, EDispatch |
|
368 } ; |
|
369 /** |
|
370 * Note that ConsumeEvent is missing so after doing this the state engine will do Dispatch |
|
371 */ |
|
372 const STATE_ELEMENT InTouchArea__ResistiveUp[1] = { |
|
373 0, 0, EDispatch |
|
374 } ; |
|
375 |
|
376 /** |
|
377 * All the rest of the events are errors so produce error entry to log and |
|
378 * stay in the InTouchArea state |
|
379 */ |
|
380 const STATE_ELEMENT InTouchAreaErrorEvent[2] = { |
|
381 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
382 0, ACT(ErrorEvent), EInTouchArea |
|
383 }; |
|
384 |
|
385 const STATE InTouchArea__[7] = { |
|
386 EDown, InTouchAreaErrorEvent, |
|
387 EDrag, InTouchArea__Drag, |
|
388 ECapacitiveUP, InTouchArea__CapacitiveUp, |
|
389 EResistiveUP, InTouchArea__ResistiveUp, |
|
390 ETouchTimer, InTouchAreaErrorEvent, |
|
391 EHoldTimer, InTouchAreaErrorEvent, |
|
392 ESuppressTimer, InTouchAreaErrorEvent |
|
393 }; |
|
394 |
|
395 |
|
396 /*! |
|
397 * :Suppress_D state end its elements |
|
398 * Here Down and suppress timers are OK. |
|
399 */ |
|
400 |
|
401 /*! |
|
402 * Down will be handled as a Drag event in the Dispatch state. |
|
403 */ |
|
404 const STATE_ELEMENT Suppress_D__Down[4] = { |
|
405 0, ACT(ClearSuppressTimer), Eignore, |
|
406 0, ACT(RenameToDrag), EDispatch |
|
407 } ; |
|
408 /*! |
|
409 * Suppress timer will generate Release UI event. |
|
410 */ |
|
411 const STATE_ELEMENT Suppress_D__SuppressTimer[3] = { |
|
412 0, ACT(ConsumeEvent), Eignore, |
|
413 0, ACT(ClearSuppressTimer), Eignore, |
|
414 0, ACT(ProduceRelease), EInit, |
|
415 } ; |
|
416 |
|
417 /** |
|
418 * All the rest of the events are errors so produce error entry to log and |
|
419 * stay in the Suppress_D state |
|
420 */ |
|
421 const STATE_ELEMENT Suppress_DErrorEvent[2] = { |
|
422 0, ACT(ConsumeEvent), Eignore, // remember to consume event, otherwise state machine will loop... |
|
423 0, ACT(ErrorEvent), ESuppress_D |
|
424 }; |
|
425 |
|
426 const STATE Suppress_D__[7] = { |
|
427 EDown, Suppress_D__Down, |
|
428 EDrag, Suppress_DErrorEvent, |
|
429 ECapacitiveUP, Suppress_DErrorEvent, |
|
430 EResistiveUP, Suppress_DErrorEvent, |
|
431 ETouchTimer, Suppress_DErrorEvent, |
|
432 EHoldTimer, Suppress_DErrorEvent, |
|
433 ESuppressTimer, Suppress_D__SuppressTimer |
|
434 }; |
|
435 /*! |
|
436 * The allStates array contains all the possible states of the state machine. |
|
437 */ |
|
438 const STATE* const allStates[8] = |
|
439 { |
|
440 Ignore__, |
|
441 Init__, |
|
442 Dispatch__, |
|
443 InTouchTime__, |
|
444 InHoldTime_U__, |
|
445 InHoldTime_D__, |
|
446 InTouchArea__, |
|
447 Suppress_D__ |
|
448 }; |
|
449 /*! |
|
450 * stateNames are used in the logging |
|
451 */ |
|
452 #ifdef GESTURE_LOGGING |
|
453 const char* const stateNames[8] = |
|
454 { |
|
455 "Ignore", |
|
456 "Init", |
|
457 "Dispatch", |
|
458 "InTouchTime", |
|
459 "InHoldTime_U", |
|
460 "InHoldTime_D", |
|
461 "InTouchArea", |
|
462 "Suppress" |
|
463 }; |
|
464 |
|
465 // event names are also used in logging |
|
466 const char* const hweventNames[] = { |
|
467 "EDown", |
|
468 "EDrag", |
|
469 "ECapacitiveUP", |
|
470 "EResistiveUP", |
|
471 "ETouchTimer", |
|
472 "EHoldTimer", |
|
473 "ESuppressTimer" |
|
474 } ; |
|
475 #endif |
|
476 |
|
477 /*! CStateEngine contains the methods used in the state machine implementation. |
|
478 * |
|
479 * The methods in CStateEngine used in the state machine definition are |
|
480 * either condition methods or action methods. |
|
481 * |
|
482 * Constructor |
|
483 * \param[in]: MTimerInterface atimerif. An attempt to make this more OS agnostic the actual |
|
484 * timers are accessed using a separate interface. |
|
485 */ |
|
486 CStateEngine::CStateEngine(CStateEngineConfiguration* aConfig, MTimerInterface* atimerif, int aIndex) |
|
487 { |
|
488 m_config = aConfig ; |
|
489 m_timerif = atimerif ; |
|
490 m_currentState = EInit ; |
|
491 m_index = aIndex ; |
|
492 isStatemachineBlocked = false; |
|
493 } |
|
494 |
|
495 CStateEngine::~CStateEngine() |
|
496 { |
|
497 // Just to be sure... |
|
498 iTouchPoints.Reset() ; |
|
499 iDragPoints.ResetAndDestroy() ; |
|
500 } |
|
501 /*! |
|
502 * ConsumeEvent: the method defines that the turnStateMachine will stop the processing |
|
503 * of the state methods after it has reached the next state. |
|
504 * |
|
505 */ |
|
506 void CStateEngine::ConsumeEvent() |
|
507 { |
|
508 m_eventConsumed = true ; |
|
509 } |
|
510 /*! |
|
511 * Condition method |
|
512 * \return true, if the touch timer limit > 0 |
|
513 */ |
|
514 bool CStateEngine::IsTouchTimer() |
|
515 { |
|
516 bool isit = (m_config->m_touchTimerLimit > 0) ; |
|
517 |
|
518 return isit ; |
|
519 } |
|
520 /*! |
|
521 * Condition method |
|
522 * \return true, if the hold timer limit > 0 |
|
523 */ |
|
524 bool CStateEngine::IsHoldTimer() |
|
525 { |
|
526 bool isit = (m_config->m_holdTimerLimit > 0) ; |
|
527 |
|
528 return isit ; |
|
529 } |
|
530 /*! |
|
531 * Condition method |
|
532 * \return true, if the suppress timer limit > 0 |
|
533 */ |
|
534 bool CStateEngine::IsSuppressTimer() |
|
535 { |
|
536 bool isit = (m_config->m_suppressTimerLimit > 0) ; |
|
537 |
|
538 return isit ; |
|
539 } |
|
540 /*! |
|
541 * Condition method |
|
542 * \return true, if the touch area has been defined (the touch tolerancelength > 0) |
|
543 */ |
|
544 bool CStateEngine::IsTouchTimeArea() |
|
545 { |
|
546 bool isit = (m_config->m_touchTimeTolerance.iX > 0) ; |
|
547 return isit ; |
|
548 } |
|
549 /*! |
|
550 * Condition method |
|
551 * \return true, if the touch area has been defined (the touch tolerancelength > 0) |
|
552 */ |
|
553 bool CStateEngine::IsTouchArea() |
|
554 { |
|
555 bool isit = (m_config->m_touchTolerance.iX > 0) ; |
|
556 return isit ; |
|
557 } |
|
558 /*! |
|
559 * Condition method |
|
560 * \return true, if the hold area has been defined (the hold tolerancelength > 0) |
|
561 */ |
|
562 bool CStateEngine::IsHoldArea() |
|
563 { |
|
564 bool isit = (m_config->m_holdTolerance.iX > 0) ; |
|
565 return isit ; |
|
566 } |
|
567 |
|
568 bool CStateEngine::InsideArea(const TPoint& point, |
|
569 const TRect& rect, |
|
570 TAreaShape shape, |
|
571 const TPoint& tolerance) |
|
572 { |
|
573 bool isit; |
|
574 switch(shape) |
|
575 { |
|
576 default: // pass trough |
|
577 case ERectangle: |
|
578 { |
|
579 isit = rect.Contains(m_hwe.iPosition) ; |
|
580 break ; |
|
581 } |
|
582 case ECircle: |
|
583 { |
|
584 TPoint delta = m_hwe.iPosition - point; |
|
585 long circlepoint = delta.iX * delta.iX + delta.iY * delta.iY; |
|
586 isit = (circlepoint < tolerance.iX * tolerance.iX); |
|
587 break ; |
|
588 } |
|
589 case EEllipse: |
|
590 { |
|
591 int asquare = tolerance.iX * tolerance.iX ; |
|
592 int bsquare = tolerance.iY * tolerance.iY ; |
|
593 TPoint delta = m_hwe.iPosition - point; |
|
594 int result = (delta.iX * delta.iX) * bsquare + (delta.iY * delta.iY) * asquare; |
|
595 |
|
596 isit = (result < asquare * bsquare); |
|
597 break ; |
|
598 } |
|
599 } |
|
600 return isit ; |
|
601 } |
|
602 |
|
603 /*! |
|
604 * Condition method |
|
605 * Check if the current event is positioned inside the touch area. |
|
606 * Touch area can be a rectangle, a circle or an ellipse, so different |
|
607 * calculation needs to be done based on the shape of the area. |
|
608 */ |
|
609 bool CStateEngine::InsideTouchTimeArea() |
|
610 { |
|
611 return InsideArea(m_touchCentre, m_touchRect, |
|
612 m_config->m_touchAreaShape, m_config->m_touchTimeTolerance); |
|
613 } |
|
614 /*! |
|
615 * Condition method |
|
616 * Check if the current event is positioned inside the touch area. |
|
617 * Touch area can be a rectangle, a circle or an ellipse, so different |
|
618 * calculation needs to be done based on the shape of the area. |
|
619 */ |
|
620 bool CStateEngine::InsideTouchArea() |
|
621 { |
|
622 return InsideArea(m_touchCentre, m_touchRect, |
|
623 m_config->m_touchAreaShape, m_config->m_touchTolerance); |
|
624 } |
|
625 /*! |
|
626 * Condition method |
|
627 * Check if the current event is positioned inside the hold area. |
|
628 * Hold area can be a rectangle, a circle or an ellipse, so different |
|
629 * calculation needs to be done based on the shape of the area. |
|
630 */ |
|
631 bool CStateEngine::InsideHoldArea() |
|
632 { |
|
633 return InsideArea(m_holdCentre, m_holdRect, |
|
634 m_config->m_holdAreaShape, m_config->m_holdTolerance); |
|
635 } |
|
636 /*! |
|
637 * Condition method |
|
638 * Check if the gesture looks like a hold, i.e. the movement has stopped. |
|
639 * \sa isNewHoldingPoint |
|
640 */ |
|
641 bool CStateEngine::LooksLikeHold() |
|
642 { |
|
643 bool isit = isNewHoldingPoint() ; |
|
644 return isit ; |
|
645 } |
|
646 /*! |
|
647 * Action method |
|
648 * Error logging. |
|
649 */ |
|
650 void CStateEngine::ErrorEvent() |
|
651 { |
|
652 // Log the error |
|
653 if (m_config->m_enableLogging) |
|
654 { |
|
655 LOGARG("ErrorEvent: %s %s", stateNames[m_currentState], hweventNames[m_hwe.iType]) ; |
|
656 } |
|
657 } |
|
658 /*! |
|
659 * Action method |
|
660 * Initialize touch timer. At the same time calculate also the touch rectangle. |
|
661 */ |
|
662 void CStateEngine::InitTouchTimer() |
|
663 { |
|
664 m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ; |
|
665 m_touchCentre = m_hwe.iPosition ; |
|
666 m_timerif->startTouchTimer(m_config->m_touchTimerLimit, m_index) ; |
|
667 } |
|
668 /*! |
|
669 * Action method. |
|
670 * Initialize hold timer. At the same time calculate also the hold rectangle. |
|
671 */ |
|
672 void CStateEngine::InitHoldTimer() |
|
673 { |
|
674 m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ; |
|
675 m_holdCentre = m_hwe.iPosition ; |
|
676 m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ; |
|
677 } |
|
678 /*! |
|
679 * Action method |
|
680 * Restart the hold timer using the hold timer limit. |
|
681 */ |
|
682 void CStateEngine::RestartHoldTimer() |
|
683 { |
|
684 m_timerif->startHoldTimer(m_config->m_holdTimerLimit, m_index) ; |
|
685 } |
|
686 /*! |
|
687 * Action method |
|
688 * Initialize suppression timer. This timer is used during touch detection when |
|
689 * resistive UP has been detected. If new DOWN comes while timer is running, it is ignored. |
|
690 */ |
|
691 void CStateEngine::InitTouchSuppressTimer() |
|
692 { |
|
693 m_timerif->startSuppressTimer(m_config->m_suppressTimerLimit, m_index) ; |
|
694 } |
|
695 /*! |
|
696 * Action method. |
|
697 * Initialize suppression timer after move. Tests show that when user is using light touch and |
|
698 * moving finger to opposite directions there may be accidental ups and downs where the time between |
|
699 * up and down may be well over 120 ms. |
|
700 */ |
|
701 void CStateEngine::InitMoveSuppressTimer() |
|
702 { |
|
703 m_timerif->startSuppressTimer(m_config->m_moveSuppressTimerLimit, m_index) ; |
|
704 } |
|
705 /*! |
|
706 * Action method |
|
707 * Stop the touch timer. |
|
708 */ |
|
709 void CStateEngine::ClearTouchTimer() |
|
710 { |
|
711 m_timerif->cancelTouchTimer(m_index) ; |
|
712 } |
|
713 /*! |
|
714 * Action method |
|
715 * Stop the hold timer. |
|
716 */ |
|
717 void CStateEngine::ClearHoldTimer() |
|
718 { |
|
719 m_timerif->cancelHoldTimer(m_index) ; |
|
720 } |
|
721 /*! |
|
722 * Action method |
|
723 * Stop the suppress timer. |
|
724 */ |
|
725 void CStateEngine::ClearSuppressTimer() |
|
726 { |
|
727 m_timerif->cancelSuppressTimer(m_index) ; |
|
728 } |
|
729 /*!Helper method. |
|
730 * Create UI event |
|
731 * \param code The new UI event type (Touch, Release, Move, Hold) |
|
732 */ |
|
733 CUiEvent* CStateEngine::createUIEventL(TUiEventCode code, const TPoint& aPos) |
|
734 { |
|
735 |
|
736 m_previousUiGenerated = code ; |
|
737 return CUiEvent::NewL(code, m_gestureStartXY, aPos, getPreviousXY(aPos), |
|
738 isTimerMessage(), m_hwe.iTarget, getInterval(), m_index, m_hwe.iTime.Int64()) ; |
|
739 } |
|
740 /*! |
|
741 * Return the previous XY position and store the current for next round |
|
742 */ |
|
743 TPoint CStateEngine::getPreviousXY(const TPoint& aCurrentXY) |
|
744 { |
|
745 TPoint p = m_previousXY ; |
|
746 m_previousXY = aCurrentXY ; |
|
747 return p ; |
|
748 } |
|
749 /*! |
|
750 * \return true, if the current event was timer triggered |
|
751 */ |
|
752 bool CStateEngine::isTimerMessage() |
|
753 { |
|
754 return (m_hwe.iType >= ETouchTimer); // NOTE: if new events are added at the end of the list this needs to be changed |
|
755 } |
|
756 /*! |
|
757 * Action method. |
|
758 * Generate the Touch UI event. |
|
759 * If there are a set of touch points collected, calculate the position to the |
|
760 * Touch UI event to be the average of the collected points. |
|
761 */ |
|
762 void CStateEngine::ProduceTouch() |
|
763 { |
|
764 m_wasFiltered = false ; |
|
765 CUiEvent* cue = NULL; |
|
766 getInterval() ; // dummy call to initialize the variable.... |
|
767 TInt err(KErrNone); |
|
768 if (iTouchPoints.Count()>0) |
|
769 { |
|
770 // calculate average of the touch points |
|
771 m_currentTouchXY = calculateTouchAverageFromPoints() ; |
|
772 TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_currentTouchXY)) ; |
|
773 } |
|
774 else |
|
775 { |
|
776 TRAP(err, cue = createUIEventL(stmUiEventEngine::ETouch, m_uiEventXY)) ; |
|
777 } |
|
778 if(!err) |
|
779 m_config->m_uiEventSender->AddEvent(cue) ; |
|
780 } |
|
781 /*! |
|
782 * Action method |
|
783 * Generate the Move UI event. The position of the event has been set in the SetCurrentPos |
|
784 * The previous position needs some special handling, if filtering has been used. |
|
785 * \sa SetCurrentPos |
|
786 */ |
|
787 void CStateEngine::ProduceMove() |
|
788 { |
|
789 m_wasFiltered = false ; |
|
790 if (m_uiEventXY == m_previousXY) { |
|
791 return; |
|
792 } |
|
793 CUiEvent* cue = NULL; |
|
794 TRAPD(err, cue = createUIEventL(stmUiEventEngine::EMove, m_uiEventXY)) ; |
|
795 |
|
796 if(!err) |
|
797 m_config->m_uiEventSender->AddEvent(cue) ; |
|
798 } |
|
799 /*! |
|
800 * Action method |
|
801 * Generate the Release UI event. |
|
802 */ |
|
803 void CStateEngine::ProduceRelease() |
|
804 { |
|
805 m_wasFiltered = false ; |
|
806 CUiEvent* cue = NULL; |
|
807 TRAPD(err, cue = createUIEventL(stmUiEventEngine::ERelease, m_uiEventXY)) ; |
|
808 if(!err) |
|
809 m_config->m_uiEventSender->AddEvent(cue) ; |
|
810 |
|
811 if (m_config->m_enableLogging) |
|
812 { |
|
813 LOGFLUSH ; |
|
814 } |
|
815 } |
|
816 /*! |
|
817 * Action method |
|
818 * Generate the Hold UI event. |
|
819 */ |
|
820 void CStateEngine::ProduceHold() |
|
821 { |
|
822 m_wasFiltered = false ; |
|
823 CUiEvent* cue = NULL; |
|
824 TRAPD(err, cue = createUIEventL(stmUiEventEngine::EHold, m_holdCentre)) ; |
|
825 if(!err) |
|
826 m_config->m_uiEventSender->AddEvent(cue) ; |
|
827 |
|
828 } |
|
829 /*! |
|
830 * Action method |
|
831 * Rename the current event to drag. This is used when the accidental up/down message pair |
|
832 * has been detected, the DOWN event is handled as it were a move event. |
|
833 */ |
|
834 void CStateEngine::RenameToDrag() |
|
835 { |
|
836 m_hwe.iType = stmUiEventEngine::EDrag ; |
|
837 } |
|
838 /*! |
|
839 * Action method |
|
840 * Initialize the touch time area. Clear the array for collected touch points and |
|
841 * calculate the touch rectangle. |
|
842 */ |
|
843 void CStateEngine::PrepareTouchTimeArea() |
|
844 { |
|
845 if (iTouchPoints.Count()>0) iTouchPoints.Reset() ; |
|
846 m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTimeTolerance) ; |
|
847 } |
|
848 |
|
849 /*! |
|
850 * Action method |
|
851 * Initialize the touch area. Clear the array for collected touch points and |
|
852 * calculate the touch rectangle. |
|
853 */ |
|
854 void CStateEngine::PrepareTouchArea() |
|
855 { |
|
856 if (iTouchPoints.Count()>0) iTouchPoints.Reset() ; |
|
857 m_touchRect = ToleranceRect(m_hwe.iPosition, m_config->m_touchTolerance) ; |
|
858 } |
|
859 /*! |
|
860 * Action method |
|
861 * Initialize the hold area rectangle. |
|
862 */ |
|
863 void CStateEngine::PrepareHoldArea() |
|
864 { |
|
865 m_holdRect = ToleranceRect(m_hwe.iPosition, m_config->m_holdTolerance) ; |
|
866 } |
|
867 /*! |
|
868 * Action method |
|
869 * Store the current position and time always when we see EDrag. The stored value is used |
|
870 * to calculate correct speed after filtered messages. |
|
871 */ |
|
872 void CStateEngine::StoreMovePos() |
|
873 { |
|
874 if (m_config->m_enableLogging) |
|
875 { |
|
876 LOGARG("store move pos from (%d, %d) to (%d, %d)", |
|
877 m_lastFilteredPosition.iX, m_lastFilteredPosition.iY,m_hwe.iPosition.iX, |
|
878 m_hwe.iPosition.iY ) ; |
|
879 } |
|
880 m_lastFilteredPosition = m_hwe.iPosition ; |
|
881 m_lastFilteredMessageTime = m_hwe.iTime ; |
|
882 |
|
883 } |
|
884 /*! |
|
885 * Action method |
|
886 * Store the current position and time. |
|
887 */ |
|
888 void CStateEngine::SetCurrentPos() |
|
889 { |
|
890 m_uiEventXY = m_hwe.iPosition ; |
|
891 } |
|
892 /*! |
|
893 * Action method |
|
894 * Initialize the gesture starting. |
|
895 */ |
|
896 void CStateEngine::SetGestureStart() |
|
897 { |
|
898 m_gestureStartXY = m_hwe.iPosition ; |
|
899 m_previousXY = m_hwe.iPosition ; |
|
900 m_gestureTarget = m_hwe.iTarget ; |
|
901 iDragPoints.ResetAndDestroy() ; |
|
902 iTouchPoints.Reset() ; |
|
903 } |
|
904 /*! |
|
905 * Action method |
|
906 * Add current point to the set of touch points. |
|
907 */ |
|
908 void CStateEngine::AddToTouch() |
|
909 { |
|
910 iTouchPoints.Append(THwEvent(m_hwe.iType, |
|
911 m_hwe.iPosition, |
|
912 m_hwe.iTime, |
|
913 m_hwe.iTarget, |
|
914 m_index) |
|
915 ) ; |
|
916 // calculate the average of touch points and move the touch area accordingly |
|
917 // this allows slight movement of the figertip while inside touch time |
|
918 if (iTouchPoints.Count()>2) |
|
919 { |
|
920 TPoint newtp = calculateTouchAverageFromPoints() ; |
|
921 m_touchRect = ToleranceRect(newtp, m_config->m_touchTolerance) ; |
|
922 m_holdRect = ToleranceRect(newtp, m_config->m_holdTolerance) ; |
|
923 } |
|
924 } |
|
925 /*! |
|
926 * Action method |
|
927 * Add the current point to the set of dragging points. |
|
928 * The set of dragging points is examined to determine if a enw hold has been started. |
|
929 */ |
|
930 void CStateEngine::AddDraggingPos() |
|
931 { |
|
932 iDragPoints.Append(new THwEvent(m_hwe.iType, |
|
933 m_hwe.iPosition, |
|
934 m_hwe.iTime, |
|
935 m_hwe.iTarget, |
|
936 m_index) |
|
937 ) ; |
|
938 } |
|
939 /*! |
|
940 * HandleStateEvent processes one event, which can be either pointer event or timer event. |
|
941 * The event is handled by calling the turnStateMachine method. |
|
942 */ |
|
943 bool CStateEngine::handleStateEvent() |
|
944 { |
|
945 // We get an event into m_hwe by this moment, lets kick the state machine |
|
946 m_wasFiltered = ETrue ; |
|
947 if (isStatemachineBlocked) |
|
948 return m_wasFiltered; |
|
949 |
|
950 CalculateDelta() ; |
|
951 turnStateMachine(); |
|
952 |
|
953 m_previousPointerEventPosition = m_hwe.iPosition ; |
|
954 return m_wasFiltered ; |
|
955 } |
|
956 |
|
957 /*! |
|
958 * Get the current touch rectangle. If touch state not currently on, returns TRect(TPoint(0,0),TPoint(0,0)) |
|
959 * (touch state meaning that the touch timer is still running and the points have been kept inside the area) |
|
960 */ |
|
961 TRect CStateEngine::getTouchArea() |
|
962 { |
|
963 return m_touchRect ; |
|
964 } |
|
965 /*! |
|
966 * get the hold area rectangle |
|
967 */ |
|
968 TRect CStateEngine::getHoldArea() |
|
969 { |
|
970 return m_holdRect ; |
|
971 } |
|
972 /*! |
|
973 * MStateMachine method. |
|
974 */ |
|
975 bool CStateEngine::wasLastMessageFiltered() |
|
976 { |
|
977 return m_wasFiltered ; |
|
978 } |
|
979 |
|
980 /*! |
|
981 * Check if the last X points in the stored points look like the movement has stopped |
|
982 */ |
|
983 bool CStateEngine::isNewHoldingPoint() |
|
984 { |
|
985 int x = iDragPoints.Count(); |
|
986 if (x > 2) // are there any points to be checked? |
|
987 { |
|
988 THwEvent* phwe = iDragPoints[x-1] ; |
|
989 THwEvent* phweinsidehold = phwe ; |
|
990 TRect recth = ToleranceRect(phwe->iPosition, m_config->m_holdTolerance) ; |
|
991 // Look backwards from the last point to see if there are enought points (enough in time) to look like a hold |
|
992 x -= 2 ; |
|
993 while (x > 0 && recth.Contains(iDragPoints[x]->iPosition)) |
|
994 { |
|
995 phweinsidehold = iDragPoints[x]; |
|
996 --x; |
|
997 } |
|
998 TTimeIntervalMicroSeconds tival = phwe->iTime.MicroSecondsFrom(phweinsidehold->iTime) ; |
|
999 |
|
1000 /** |
|
1001 * remove the extra points from the list if they are outside of holding area |
|
1002 */ |
|
1003 while (x > 0) |
|
1004 { |
|
1005 THwEvent* p = iDragPoints[x] ; |
|
1006 delete p ; |
|
1007 iDragPoints.Remove(x) ; |
|
1008 --x ; |
|
1009 } |
|
1010 |
|
1011 // See the time difference of the two points which still are inside the hold area |
|
1012 TTimeIntervalMicroSeconds limit = m_config->m_holdTimerLimit/2 ; |
|
1013 if (tival > limit) |
|
1014 { |
|
1015 if (m_config->m_enableLogging) |
|
1016 { |
|
1017 LOGARG("isNewHoldingPoint: %s, dragpoints count %d", |
|
1018 stateNames[m_currentState], iDragPoints.Count()) ; |
|
1019 } |
|
1020 return true ; |
|
1021 } |
|
1022 } |
|
1023 else |
|
1024 { |
|
1025 // one or 0 points does not look like hold |
|
1026 |
|
1027 } |
|
1028 return false ; |
|
1029 } |
|
1030 /*! |
|
1031 * calculate simple average of the touch points, i.e. calculate the average of the previous and current |
|
1032 * position. Note that the touch point remains the same, this just calculates new value for the UI position |
|
1033 */ |
|
1034 void CStateEngine::CalculateTouchAverage() |
|
1035 { |
|
1036 m_uiEventXY.iX = (m_uiEventXY.iX+m_hwe.iPosition.iX)/2 ; |
|
1037 m_uiEventXY.iY = (m_uiEventXY.iY+m_hwe.iPosition.iY)/2 ; |
|
1038 } |
|
1039 /*! |
|
1040 * Calculate the movement vector. |
|
1041 */ |
|
1042 void CStateEngine::CalculateDelta() |
|
1043 { |
|
1044 m_deltaVector.iX = m_hwe.iPosition.iX-m_previousPointerEventPosition.iX ; |
|
1045 m_deltaVector.iY = m_hwe.iPosition.iY-m_previousPointerEventPosition.iY ; |
|
1046 } |
|
1047 /*!internal |
|
1048 * Debug logging method |
|
1049 */ |
|
1050 void CStateEngine::DebugPrintState(TStateMachineState anextstate) |
|
1051 { |
|
1052 if (m_config->m_enableLogging) |
|
1053 { |
|
1054 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", |
|
1055 stateNames[m_currentState], |
|
1056 m_uiEventXY.iX, m_uiEventXY.iY, |
|
1057 m_touchRect.iTl.iX, m_touchRect.iTl.iY,m_touchRect.iBr.iX, m_touchRect.iBr.iY, |
|
1058 m_holdRect.iTl.iX, m_holdRect.iTl.iY,m_holdRect.iBr.iX, m_holdRect.iBr.iY, |
|
1059 m_gestureStartXY.iX, m_gestureStartXY.iY, |
|
1060 m_deltaVector.iX, m_deltaVector.iY, |
|
1061 m_hwe.iPosition.iX, m_hwe.iPosition.iY, hweventNames[m_hwe.iType], |
|
1062 stateNames[anextstate] |
|
1063 ); |
|
1064 } |
|
1065 } |
|
1066 |
|
1067 /*! |
|
1068 * calculate the rectangle for touch or hold |
|
1069 */ |
|
1070 TRect CStateEngine::ToleranceRect(const TPoint& aCenterPoint, const TPoint& tolerance) |
|
1071 { |
|
1072 // grow by the tolerance length, while keeping the center point |
|
1073 TRect toleranceRect( |
|
1074 aCenterPoint - tolerance, |
|
1075 aCenterPoint + tolerance); |
|
1076 return toleranceRect; |
|
1077 } |
|
1078 /*! |
|
1079 * turnStateMachine. Go trough the state elements found for the current event |
|
1080 * until the event has been consumed. |
|
1081 * |
|
1082 * \pre m_currentState defines the current state and the index to the allStates array. |
|
1083 * \pre m_hwe is the message being handled. The corresponding STATE_ELEMENT array must be found and processed. |
|
1084 * |
|
1085 */ |
|
1086 void CStateEngine::turnStateMachine() |
|
1087 { |
|
1088 |
|
1089 const STATE_ELEMENT* pelement ; |
|
1090 m_eventConsumed = false ; // run the loop until the event has been consumed |
|
1091 // Now run trough the motions of the state elements, and prepare to change to next state while doing so. |
|
1092 // If the state elements set the m_eventConsumed then all is done |
|
1093 isStatemachineBlocked = true; |
|
1094 while (!m_eventConsumed) |
|
1095 { |
|
1096 int i = 0 ; |
|
1097 const STATE* const pcurrentstate = allStates[m_currentState] ; |
|
1098 // Since each state definition must contain entries for all possible events the following loop cannot fail ;-) |
|
1099 while (pcurrentstate[i].theEvent != m_hwe.iType ) ++i ; |
|
1100 pelement = pcurrentstate[i].stateElements ; |
|
1101 TStateMachineState nextState = Eignore ; |
|
1102 /* |
|
1103 * Handle the individual state elements. If there is a condition function, |
|
1104 * call the function and if it returns true, handle the action function and possible next state |
|
1105 * if the condition returns false, continue to next element |
|
1106 * if there is no condition, run the action function if it exists. |
|
1107 * if the next state is defined (i.e it is != Eignore), go to that state |
|
1108 */ |
|
1109 while (nextState == Eignore) |
|
1110 { |
|
1111 condition_t cndfunc = pelement->conditionFunction ; |
|
1112 action_t actfunc = pelement->actionFunction ; |
|
1113 if (cndfunc != 0) |
|
1114 { |
|
1115 /* |
|
1116 * There was a condition function, call it to see whether the action needs to performed and/or the next satte defined |
|
1117 */ |
|
1118 if (cndfunc(this)) |
|
1119 { |
|
1120 // Condition was true, handle it |
|
1121 // call the action if it exists |
|
1122 if (actfunc != 0) actfunc(this) ; |
|
1123 // and now get to the next state |
|
1124 nextState = pelement->nextState ; // Note that while this remains Eignore there are elements to be run |
|
1125 } |
|
1126 } |
|
1127 else |
|
1128 { |
|
1129 /** |
|
1130 * No condition function, call the possible action function and get the next state |
|
1131 */ |
|
1132 if (actfunc != 0) actfunc(this) ; |
|
1133 nextState = pelement->nextState ; // Note that while this remains Eignore there are elements to be run |
|
1134 } |
|
1135 ++pelement ; // next entry in the elements |
|
1136 } |
|
1137 if (m_config->m_enableLogging) DebugPrintState(nextState) ; |
|
1138 m_currentState = nextState ; // Change to the next state |
|
1139 } |
|
1140 isStatemachineBlocked = false; |
|
1141 } |
|
1142 TTimeIntervalMicroSeconds CStateEngine::getInterval() |
|
1143 { |
|
1144 TTime now ; |
|
1145 now.HomeTime() ; |
|
1146 TTimeIntervalMicroSeconds interval = now.MicroSecondsFrom(m_lastMessageTime) ; |
|
1147 m_lastMessageTime = now ; |
|
1148 return interval ; |
|
1149 } |
|
1150 |
|
1151 TPoint CStateEngine::calculateTouchAverageFromPoints() |
|
1152 { |
|
1153 TPoint tp ; |
|
1154 int count = iTouchPoints.Count() ; |
|
1155 for (int i = 0; i < count; i++) |
|
1156 { |
|
1157 tp += iTouchPoints[i].iPosition; |
|
1158 } |
|
1159 if(count) |
|
1160 { |
|
1161 tp.iX /= count ; |
|
1162 tp.iY /= count ; |
|
1163 } |
|
1164 return tp ; |
|
1165 } |
|
1166 |