1 /*
2 * Copyright (C) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed On an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include <cfloat>
17 #include "accessibility_multifinger_multitap.h"
18 #include "hilog_wrapper.h"
19
20 namespace OHOS {
21 namespace Accessibility {
22 namespace {
23 constexpr float SLOP_DELTA = 0.5f;
24 constexpr int32_t POINTER_COUNT_1 = 1;
25 constexpr int32_t POINTER_COUNT_2 = 2;
26 constexpr int32_t POINTER_COUNT_3 = 3;
27 constexpr int32_t POINTER_COUNT_4 = 4;
28 constexpr int32_t MULTI_FINGER_MAX_CONTINUE_TAP_NUM = 3;
29 constexpr float TOUCH_SLOP = 8.0f;
30 constexpr uint32_t MIN_MOVE_POINTER_NUM = 2;
31 } // namespace
32
MultiFingerGestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> & runner,AccessibilityMultiTapGestureRecognizer & server)33 MultiFingerGestureHandler::MultiFingerGestureHandler(const std::shared_ptr<AppExecFwk::EventRunner> &runner,
34 AccessibilityMultiTapGestureRecognizer &server) : AppExecFwk::EventHandler(runner), server_(server)
35 {
36 }
37
IsTapGesture(const GestureType gestureType)38 bool MultiFingerGestureHandler::IsTapGesture(const GestureType gestureType)
39 {
40 if (gestureType == GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP_AND_HOLD ||
41 gestureType == GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP_AND_HOLD ||
42 gestureType == GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD ||
43 gestureType == GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP_AND_HOLD ||
44 gestureType == GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP_AND_HOLD ||
45 gestureType == GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD ||
46 gestureType == GestureType::GESTURE_INVALID) {
47 return false;
48 }
49
50 return true;
51 }
52
ProcessMultiFingerGestureTypeEvent(const GestureType gestureType)53 void MultiFingerGestureHandler::ProcessMultiFingerGestureTypeEvent(const GestureType gestureType)
54 {
55 HILOG_DEBUG("gesture id: %{public}d", static_cast<int32_t>(gestureType));
56
57 if (IsTapGesture(gestureType)) {
58 if (server_.GetFingerTouchUpState() == FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
59 server_.GetRecognizeListener()->MultiFingerGestureOnCompleted(gestureType);
60 server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
61 server_.Clear();
62 }
63 } else {
64 if (server_.GetFingerTouchUpState() != FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
65 if (gestureType != GestureType::GESTURE_INVALID) {
66 server_.GetRecognizeListener()->MultiFingerGestureOnCompleted(gestureType);
67 }
68 server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
69 }
70 server_.Clear();
71 }
72 }
73
ProcessMultiFingerGestureEvent(const AppExecFwk::InnerEvent::Pointer & event)74 bool MultiFingerGestureHandler::ProcessMultiFingerGestureEvent(const AppExecFwk::InnerEvent::Pointer &event)
75 {
76 HILOG_DEBUG("Inner Event Id id: %{public}u", static_cast<uint32_t>(event->GetInnerEventId()));
77
78 static std::map<uint32_t, GestureType> MULTI_GESTURE_TYPE = {
79 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_SINGLE_TAP_MSG,
80 GestureType::GESTURE_TWO_FINGER_SINGLE_TAP},
81 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
82 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_DOUBLE_TAP_MSG,
83 GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP},
84 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
85 GestureType::GESTURE_TWO_FINGER_DOUBLE_TAP_AND_HOLD},
86 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_TRIPLE_TAP_MSG,
87 GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP},
88 {AccessibilityMultiTapGestureRecognizer::TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
89 GestureType::GESTURE_TWO_FINGER_TRIPLE_TAP_AND_HOLD},
90 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_SINGLE_TAP_MSG,
91 GestureType::GESTURE_THREE_FINGER_SINGLE_TAP},
92 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
93 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_DOUBLE_TAP_MSG,
94 GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP},
95 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
96 GestureType::GESTURE_THREE_FINGER_DOUBLE_TAP_AND_HOLD},
97 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_TRIPLE_TAP_MSG,
98 GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP},
99 {AccessibilityMultiTapGestureRecognizer::THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
100 GestureType::GESTURE_THREE_FINGER_TRIPLE_TAP_AND_HOLD},
101 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_SINGLE_TAP_MSG,
102 GestureType::GESTURE_FOUR_FINGER_SINGLE_TAP},
103 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_LONG_PRESS_MSG, GestureType::GESTURE_INVALID},
104 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_DOUBLE_TAP_MSG,
105 GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP},
106 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG,
107 GestureType::GESTURE_FOUR_FINGER_DOUBLE_TAP_AND_HOLD},
108 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_TRIPLE_TAP_MSG,
109 GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP},
110 {AccessibilityMultiTapGestureRecognizer::FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG,
111 GestureType::GESTURE_FOUR_FINGER_TRIPLE_TAP_AND_HOLD}
112 };
113
114 uint32_t eventId = static_cast<uint32_t>(event->GetInnerEventId());
115 if (MULTI_GESTURE_TYPE.find(eventId) == MULTI_GESTURE_TYPE.end()) {
116 return false;
117 }
118
119 GestureType gestureType = MULTI_GESTURE_TYPE.at(eventId);
120 ProcessMultiFingerGestureTypeEvent(gestureType);
121
122 return true;
123 }
124
ProcessEvent(const AppExecFwk::InnerEvent::Pointer & event)125 void MultiFingerGestureHandler::ProcessEvent(const AppExecFwk::InnerEvent::Pointer &event)
126 {
127 HILOG_DEBUG();
128
129 if (!event) {
130 HILOG_ERROR("event is null");
131 return;
132 }
133
134 if (ProcessMultiFingerGestureEvent(event)) {
135 return;
136 }
137
138 switch (event->GetInnerEventId()) {
139 case AccessibilityMultiTapGestureRecognizer::WAIT_ANOTHER_FINGER_DOWN_MSG:
140 server_.SetFingerTouchUpState(FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP);
141 break;
142 case AccessibilityMultiTapGestureRecognizer::CANCEL_WAIT_FINGER_DOWN_MSG:
143 server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_NOT_START);
144 break;
145 case AccessibilityMultiTapGestureRecognizer::CANCEL_GESTURE:
146 if (server_.GetFingerTouchUpState() != FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
147 server_.SetFingerTouchUpState(FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP);
148 }
149 server_.GetRecognizeListener()->MultiFingerGestureOnCancelled(true);
150 server_.SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_CANCLE);
151 server_.Clear();
152 break;
153 default:
154 break;
155 }
156 }
157
AccessibilityMultiTapGestureRecognizer()158 AccessibilityMultiTapGestureRecognizer::AccessibilityMultiTapGestureRecognizer()
159 {
160 HILOG_DEBUG();
161
162 #ifdef OHOS_BUILD_ENABLE_DISPLAY_MANAGER
163 AccessibilityDisplayManager &displayMgr = Singleton<AccessibilityDisplayManager>::GetInstance();
164 auto display = displayMgr.GetDefaultDisplay();
165 if (!display) {
166 HILOG_ERROR("get display is nullptr");
167 return;
168 }
169
170 float density = display->GetVirtualPixelRatio();
171 int32_t slop = static_cast<int32_t>(density * DOUBLE_TAP_SLOP + SLOP_DELTA);
172 doubleTapOffsetThresh_ = slop;
173 touchSlop_ = TOUCH_SLOP;
174 mMinPixelsBetweenSamplesX_ = MIN_PIXELS(display->GetWidth());
175 mMinPixelsBetweenSamplesY_ = MIN_PIXELS(display->GetHeight());
176 #else
177 HILOG_DEBUG("not support display manager");
178 doubleTapOffsetThresh_ = static_cast<int32_t>(1 * DOUBLE_TAP_SLOP + SLOP_DELTA);
179 touchSlop_ = TOUCH_SLOP;
180 mMinPixelsBetweenSamplesX_ = 1;
181 mMinPixelsBetweenSamplesY_ = 1;
182 #endif
183
184 runner_ = Singleton<AccessibleAbilityManagerService>::GetInstance().GetMainRunner();
185 if (!runner_) {
186 HILOG_ERROR("get runner failed");
187 return;
188 }
189
190 handler_ = std::make_shared<MultiFingerGestureHandler>(runner_, *this);
191 if (!handler_) {
192 HILOG_ERROR("create event handler failed");
193 return;
194 }
195 }
196
RegisterListener(AccessibilityGestureRecognizeListener & listener)197 void AccessibilityMultiTapGestureRecognizer::RegisterListener(AccessibilityGestureRecognizeListener& listener)
198 {
199 HILOG_DEBUG();
200
201 listener_ = &listener;
202 }
203
CancelTwoFingerEvent()204 void AccessibilityMultiTapGestureRecognizer::CancelTwoFingerEvent()
205 {
206 HILOG_DEBUG();
207
208 if (!handler_) {
209 HILOG_ERROR("handler_ is null ptr");
210 return;
211 }
212
213 handler_->RemoveEvent(TWO_FINGER_SINGLE_TAP_MSG);
214 handler_->RemoveEvent(TWO_FINGER_LONG_PRESS_MSG);
215 handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_MSG);
216 handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
217 handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_MSG);
218 handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
219 }
220
CancelThreeFingerEvent()221 void AccessibilityMultiTapGestureRecognizer::CancelThreeFingerEvent()
222 {
223 HILOG_DEBUG();
224
225 if (!handler_) {
226 HILOG_ERROR("handler_ is null ptr");
227 return;
228 }
229
230 handler_->RemoveEvent(THREE_FINGER_SINGLE_TAP_MSG);
231 handler_->RemoveEvent(THREE_FINGER_LONG_PRESS_MSG);
232 handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_MSG);
233 handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
234 handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_MSG);
235 handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
236 }
237
CancelFourFingerEvent()238 void AccessibilityMultiTapGestureRecognizer::CancelFourFingerEvent()
239 {
240 HILOG_DEBUG();
241
242 if (!handler_) {
243 HILOG_ERROR("handler_ is null ptr");
244 return;
245 }
246
247 handler_->RemoveEvent(FOUR_FINGER_SINGLE_TAP_MSG);
248 handler_->RemoveEvent(FOUR_FINGER_LONG_PRESS_MSG);
249 handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_MSG);
250 handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
251 handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_MSG);
252 handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
253 }
254
CancelTapAndHoldGestureEvent(const int32_t fingerNum)255 void AccessibilityMultiTapGestureRecognizer::CancelTapAndHoldGestureEvent(const int32_t fingerNum)
256 {
257 HILOG_DEBUG();
258
259 switch (fingerNum) {
260 case POINTER_COUNT_2:
261 CancelTwoFingerEvent();
262 break;
263 case POINTER_COUNT_3:
264 CancelThreeFingerEvent();
265 break;
266 case POINTER_COUNT_4:
267 CancelFourFingerEvent();
268 break;
269 default:
270 break;
271 }
272 }
273
CancelHoldGestureEvent()274 void AccessibilityMultiTapGestureRecognizer::CancelHoldGestureEvent()
275 {
276 HILOG_DEBUG();
277
278 if (!handler_) {
279 HILOG_ERROR("handler_ is null ptr");
280 return;
281 }
282
283 handler_->RemoveEvent(TWO_FINGER_LONG_PRESS_MSG);
284 handler_->RemoveEvent(TWO_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
285 handler_->RemoveEvent(TWO_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
286 handler_->RemoveEvent(THREE_FINGER_LONG_PRESS_MSG);
287 handler_->RemoveEvent(THREE_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
288 handler_->RemoveEvent(THREE_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
289 handler_->RemoveEvent(FOUR_FINGER_LONG_PRESS_MSG);
290 handler_->RemoveEvent(FOUR_FINGER_DOUBLE_TAP_AND_HOLD_MSG);
291 handler_->RemoveEvent(FOUR_FINGER_TRIPLE_TAP_AND_HOLD_MSG);
292 }
293
CancelAllPenddingEvent()294 void AccessibilityMultiTapGestureRecognizer::CancelAllPenddingEvent()
295 {
296 HILOG_DEBUG();
297
298 if (!handler_) {
299 HILOG_ERROR("handler_ is null ptr");
300 return;
301 }
302
303 handler_->RemoveEvent(CANCEL_GESTURE);
304 handler_->RemoveEvent(CANCEL_WAIT_FINGER_DOWN_MSG);
305 CancelTwoFingerEvent();
306 CancelThreeFingerEvent();
307 CancelFourFingerEvent();
308 }
309
Clear()310 void AccessibilityMultiTapGestureRecognizer::Clear()
311 {
312 HILOG_DEBUG();
313
314 targetFingers_ = -1;
315 addContinueTapNum_ = 0;
316 isMoveGestureRecognizing = 0;
317 moveDirection = -1;
318 firstDownPoint_.clear();
319 lastUpPoint_.clear();
320 currentDownPoint_.clear();
321 preGesturePoint_.clear();
322 pointerRoute_.clear();
323 CancelAllPenddingEvent();
324 }
325
CancelGesture(bool isNoDelayFlag)326 void AccessibilityMultiTapGestureRecognizer::CancelGesture(bool isNoDelayFlag)
327 {
328 HILOG_DEBUG();
329
330 SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_CANCLE);
331
332 if (fingerTouchUpState_ != FingerTouchUpState::ALL_FINGER_TOUCH_UP) {
333 fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
334 }
335
336 if (!listener_) {
337 HILOG_ERROR("listener_ is null ptr");
338 return;
339 }
340
341 listener_->MultiFingerGestureOnCancelled(isNoDelayFlag);
342 Clear();
343 }
344
ParamCheck(const int32_t fingerNum)345 bool AccessibilityMultiTapGestureRecognizer::ParamCheck(const int32_t fingerNum)
346 {
347 if (static_cast<int32_t>(lastUpPoint_.size()) < fingerNum ||
348 static_cast<int32_t>(firstDownPoint_.size()) < fingerNum) {
349 HILOG_ERROR("last_up point or first_down point size is less than target fingerNum");
350 return false;
351 }
352
353 for (int pId = 0; pId < fingerNum; pId++) {
354 if (!lastUpPoint_.count(pId) || !lastUpPoint_[pId]) {
355 HILOG_ERROR("last_up point or first_down point container has wrong value and pId is: %{public}d", pId);
356 return false;
357 }
358 }
359
360 return true;
361 }
362
GetLastFirstPointUpTime(const int32_t fingerNum)363 int64_t AccessibilityMultiTapGestureRecognizer::GetLastFirstPointUpTime(const int32_t fingerNum)
364 {
365 HILOG_DEBUG();
366
367 int64_t timeRst = lastUpPoint_[0]->GetActionTime();
368 for (int32_t pId = 1; pId < fingerNum; pId++) {
369 if (lastUpPoint_[pId]->GetActionTime() < timeRst) {
370 timeRst = lastUpPoint_[pId]->GetActionTime();
371 }
372 }
373 return timeRst;
374 }
375
IsDoubelTapSlopConditionMatch(const int32_t fingerNum,const std::vector<MMI::PointerEvent::PointerItem> & curPoints,const std::vector<MMI::PointerEvent::PointerItem> & prePoints)376 bool AccessibilityMultiTapGestureRecognizer::IsDoubelTapSlopConditionMatch(const int32_t fingerNum,
377 const std::vector<MMI::PointerEvent::PointerItem> &curPoints,
378 const std::vector<MMI::PointerEvent::PointerItem> &prePoints)
379 {
380 HILOG_DEBUG("doubleTapOffsetThresh_, %{public}d", doubleTapOffsetThresh_);
381
382 std::vector<int32_t> excludePid(fingerNum, -1);
383 for (auto curPoint : curPoints) {
384 float moveDelta = FLT_MAX;
385 int32_t nearestPid = -1;
386 int32_t curX = curPoint.GetDisplayX();
387 int32_t curY = curPoint.GetDisplayY();
388 for (auto prePoint : prePoints) {
389 int32_t pId = prePoint.GetPointerId();
390 if (std::find(excludePid.begin(), excludePid.end(), pId) != excludePid.end()) {
391 continue;
392 }
393 int32_t preX = prePoint.GetDisplayX();
394 int32_t preY = prePoint.GetDisplayY();
395 int32_t offsetX = curX - preX;
396 int32_t offsetY = curY - preY;
397 if (offsetX == 0 && offsetY == 0) {
398 nearestPid = pId;
399 moveDelta = 0;
400 break;
401 }
402
403 float delta = hypot(offsetX, offsetY);
404 if (delta < moveDelta) {
405 moveDelta = delta;
406 nearestPid = pId;
407 }
408 }
409 HILOG_DEBUG("moveDelta = %{public}f, right = %{public}d", moveDelta, doubleTapOffsetThresh_ * fingerNum);
410 if (moveDelta < doubleTapOffsetThresh_ * fingerNum) {
411 excludePid.push_back(nearestPid);
412 } else {
413 return false;
414 }
415 }
416
417 return true;
418 }
419
GetPointerItemWithFingerNum(int32_t fingerNum,std::vector<MMI::PointerEvent::PointerItem> & curPoints,std::vector<MMI::PointerEvent::PointerItem> & prePoints,MMI::PointerEvent & event,std::map<int32_t,std::shared_ptr<MMI::PointerEvent>> & prePointsEventInfo)420 bool AccessibilityMultiTapGestureRecognizer::GetPointerItemWithFingerNum(int32_t fingerNum,
421 std::vector<MMI::PointerEvent::PointerItem> &curPoints,
422 std::vector<MMI::PointerEvent::PointerItem> &prePoints, MMI::PointerEvent &event,
423 std::map<int32_t, std::shared_ptr<MMI::PointerEvent>> &prePointsEventInfo)
424 {
425 HILOG_DEBUG();
426
427 std::vector<int32_t> pIds = event.GetPointerIds();
428 for (int32_t pId = 0; pId < fingerNum; pId++) {
429 if (!event.GetPointerItem(pIds[pId], curPoints[pId])) {
430 HILOG_ERROR("curPoint GetPointerItem(%{public}d) failed", pIds[pId]);
431 return false;
432 }
433 if (!prePointsEventInfo[pId]->GetPointerItem(prePointsEventInfo[pId]->GetPointerId(), prePoints[pId])) {
434 HILOG_ERROR("prePoint GetPointerItem(%{public}d) failed", prePointsEventInfo[pId]->GetPointerId());
435 return false;
436 }
437 }
438 return true;
439 }
440
IsMultiFingerDoubleTap(MMI::PointerEvent & event,const int32_t fingerNum)441 bool AccessibilityMultiTapGestureRecognizer::IsMultiFingerDoubleTap(MMI::PointerEvent &event,
442 const int32_t fingerNum)
443 {
444 HILOG_DEBUG("fingerNum is %{public}d", fingerNum);
445
446 if (!ParamCheck(fingerNum)) {
447 return false;
448 }
449
450 // first pointer up time to second pointer down time
451 int64_t firstUpTime = GetLastFirstPointUpTime(fingerNum);
452 int64_t durationTime = event.GetActionTime() - firstUpTime;
453 if (durationTime > DOUBLE_TAP_TIMEOUT || durationTime < MIN_DOUBLE_TAP_TIME) {
454 HILOG_WARN("durationTime[%{public}" PRId64 "] is wrong", durationTime);
455 return false;
456 }
457
458 std::vector<int32_t> pIds = event.GetPointerIds();
459 if (static_cast<int32_t>(pIds.size()) != fingerNum) {
460 return false;
461 }
462
463 std::vector<MMI::PointerEvent::PointerItem> curPoints(fingerNum);
464 std::vector<MMI::PointerEvent::PointerItem> prePoints(fingerNum);
465 if (!GetPointerItemWithFingerNum(fingerNum, curPoints, prePoints, event, firstDownPoint_)) {
466 return false;
467 }
468
469 return IsDoubelTapSlopConditionMatch(fingerNum, curPoints, prePoints);
470 }
471
HanleFirstTouchDownEvent(MMI::PointerEvent & event)472 void AccessibilityMultiTapGestureRecognizer::HanleFirstTouchDownEvent(MMI::PointerEvent &event)
473 {
474 HILOG_DEBUG("gestureState is %{public}d, touchUpState is %{public}d", multiFingerGestureState_,
475 fingerTouchUpState_);
476
477 if (multiFingerGestureState_ == MultiFingerGestureState::GESTURE_WAIT) {
478 if (event.GetPointerId() == 0) {
479 fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
480 Clear();
481 return;
482 } else if (!handler_->HasInnerEvent(WAIT_ANOTHER_FINGER_DOWN_MSG)) {
483 HILOG_DEBUG("do not have WAIT_ANOTHER_FINGER_DOWN_MSG");
484 SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_NOT_START);
485 }
486 }
487
488 // NOT_ALL_FINGER_TOUCH_UP state can not revice touch down event
489 if (fingerTouchUpState_ == FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
490 Clear();
491 return;
492 }
493
494 // start touch down, change fingerTouchUpState_ to TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP state
495 fingerTouchUpState_ = FingerTouchUpState::TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP;
496 firstDownPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
497 handler_->SendEvent(WAIT_ANOTHER_FINGER_DOWN_MSG, 0, TAP_INTERVAL_TIMEOUT / US_TO_MS);
498 if (event.GetPointerIds().size() == POINTER_COUNT_1) {
499 SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_WAIT);
500 } else if (event.GetPointerIds().size() == POINTER_COUNT_2) {
501 listener_->MultiFingerGestureOnStarted(true);
502 SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_START);
503 handler_->SendEvent(TWO_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
504 handler_->SendEvent(TWO_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
505 } else if (event.GetPointerIds().size() == POINTER_COUNT_3) {
506 listener_->MultiFingerGestureOnStarted(false);
507 handler_->SendEvent(THREE_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
508 handler_->SendEvent(THREE_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
509 } else if (event.GetPointerIds().size() == POINTER_COUNT_4) {
510 handler_->SendEvent(FOUR_FINGER_SINGLE_TAP_MSG, 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
511 handler_->SendEvent(FOUR_FINGER_LONG_PRESS_MSG, 0, LONG_PRESS_TIMEOUT / US_TO_MS);
512 } else {
513 CancelGesture(true);
514 }
515 }
516
HandleMultiTapEvent(MMI::PointerEvent & event,const int32_t fingerNum)517 void AccessibilityMultiTapGestureRecognizer::HandleMultiTapEvent(MMI::PointerEvent &event, const int32_t fingerNum)
518 {
519 HILOG_DEBUG("fingerNum is %{public}d", fingerNum);
520
521 // check is double tap
522 if (static_cast<int32_t>(firstDownPoint_.size()) == fingerNum &&
523 static_cast<int32_t>(lastUpPoint_.size()) == fingerNum &&
524 IsMultiFingerDoubleTap(event, fingerNum)) {
525 addContinueTapNum_ = addContinueTapNum_ + 1;
526 HILOG_DEBUG("two finger Double tap is recognized, addContinueTapNum %{public}d", addContinueTapNum_);
527 } else {
528 addContinueTapNum_ = 0;
529 }
530 if (fingerNum < POINTER_COUNT_2 || fingerNum > POINTER_COUNT_4) {
531 HILOG_ERROR("fingerNum: %{public}d is wrong", fingerNum);
532 return;
533 }
534 if (addContinueTapNum_ >= MULTI_FINGER_MAX_CONTINUE_TAP_NUM) {
535 HILOG_ERROR("continue tap times: %{public}u is wrong", addContinueTapNum_);
536 CancelGesture(true);
537 return;
538 }
539 uint32_t fingerNumIndex = static_cast<uint32_t>(fingerNum - 2);
540 handler_->SendEvent(GESTURE_TAP_MSG[addContinueTapNum_][fingerNumIndex], 0, DOUBLE_TAP_TIMEOUT / US_TO_MS);
541 handler_->SendEvent(GESTURE_HOLD_MSG[addContinueTapNum_][fingerNumIndex], 0, LONG_PRESS_TIMEOUT / US_TO_MS);
542 }
543
HandleContinueTouchDownEvent(MMI::PointerEvent & event)544 void AccessibilityMultiTapGestureRecognizer::HandleContinueTouchDownEvent(MMI::PointerEvent &event)
545 {
546 HILOG_DEBUG("fingerNum is %{public}d, gestureState is %{public}d, touchUpstate is %{public}d",
547 targetFingers_, multiFingerGestureState_, fingerTouchUpState_);
548
549 if (targetFingers_ == POINTER_COUNT_1) {
550 return;
551 }
552
553 if (multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
554 CancelGesture(true);
555 return;
556 }
557
558 if (fingerTouchUpState_ == FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP) {
559 CancelGesture(true);
560 return;
561 }
562
563 fingerTouchUpState_ = FingerTouchUpState::TOUCH_DOWN_AFTER_ALL_FINGER_TOUCH_UP;
564 int32_t pointerSize = static_cast<int32_t>(event.GetPointerIds().size());
565 if (pointerSize < targetFingers_) {
566 handler_->SendEvent(CANCEL_GESTURE, 0, TAP_INTERVAL_TIMEOUT / US_TO_MS);
567 } else if (pointerSize == targetFingers_) {
568 HandleMultiTapEvent(event, targetFingers_);
569 } else {
570 HILOG_DEBUG("current fingers is more than last touch down finger nums");
571 CancelGesture(true);
572 }
573 }
574
storeBaseDownPoint()575 void AccessibilityMultiTapGestureRecognizer::storeBaseDownPoint()
576 {
577 HILOG_DEBUG();
578
579 for (auto iter : currentDownPoint_) {
580 Pointer mp;
581 MMI::PointerEvent::PointerItem pointerIterm;
582 std::vector<Pointer> mpVec;
583 int32_t pId = iter.first;
584
585 if (!iter.second->GetPointerItem(pId, pointerIterm)) {
586 HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
587 return;
588 }
589
590 mp.px_ = static_cast<float>(pointerIterm.GetDisplayX());
591 mp.py_ = static_cast<float>(pointerIterm.GetDisplayY());
592 mpVec.push_back(mp);
593 pointerRoute_.insert(std::make_pair(pId, mpVec));
594 }
595 }
596
GetSwipeDirection(const int32_t dx,const int32_t dy)597 int32_t AccessibilityMultiTapGestureRecognizer::GetSwipeDirection(const int32_t dx, const int32_t dy)
598 {
599 HILOG_DEBUG();
600
601 if (abs(dx) > abs(dy)) {
602 return (dx < 0) ? MoveGirectionType::SWIPE_LEFT : MoveGirectionType::SWIPE_RIGHT;
603 } else {
604 return (dy < 0) ? MoveGirectionType::SWIPE_UP : MoveGirectionType::SWIPE_DOWN;
605 }
606 }
607
SaveMoveGesturePointerInfo(MMI::PointerEvent & event,const int32_t pId,const MMI::PointerEvent::PointerItem & pointerIterm,const int32_t dx,const int32_t dy)608 void AccessibilityMultiTapGestureRecognizer::SaveMoveGesturePointerInfo(MMI::PointerEvent &event,
609 const int32_t pId, const MMI::PointerEvent::PointerItem &pointerIterm, const int32_t dx, const int32_t dy)
610 {
611 HILOG_DEBUG();
612
613 int32_t currentDirection = GetSwipeDirection(dx, dy);
614 if (!isMoveGestureRecognizing) {
615 storeBaseDownPoint();
616 moveDirection = currentDirection;
617 isMoveGestureRecognizing = true;
618 return;
619 }
620
621 if (moveDirection != currentDirection) {
622 CancelGesture(true);
623 return;
624 }
625 Pointer mp;
626 mp.px_ = static_cast<float>(pointerIterm.GetDisplayX());
627 mp.py_ = static_cast<float>(pointerIterm.GetDisplayY());
628 pointerRoute_[pId].push_back(mp);
629 //update preGesturePoint_
630 preGesturePoint_[pId] = std::make_shared<MMI::PointerEvent>(event);
631 }
632
GetBasePointItem(MMI::PointerEvent::PointerItem & basePointerIterm,int32_t pId,std::map<int32_t,std::shared_ptr<MMI::PointerEvent>> & pointInfo)633 bool AccessibilityMultiTapGestureRecognizer::GetBasePointItem(MMI::PointerEvent::PointerItem &basePointerIterm,
634 int32_t pId, std::map<int32_t, std::shared_ptr<MMI::PointerEvent>> &pointInfo)
635 {
636 HILOG_DEBUG();
637
638 if (pointInfo.count(pId) == 0 || !pointInfo[pId]) {
639 return false;
640 }
641 if (!pointInfo[pId]->GetPointerItem(pointInfo[pId]->GetPointerId(), basePointerIterm)) {
642 HILOG_ERROR("base down point get GetPointerItem(%{public}d) failed", pId);
643 return false;
644 }
645
646 return true;
647 }
648
HandleMultiFingerMoveEvent(MMI::PointerEvent & event)649 void AccessibilityMultiTapGestureRecognizer::HandleMultiFingerMoveEvent(MMI::PointerEvent &event)
650 {
651 int32_t pIdSize = static_cast<int32_t>(event.GetPointerIds().size());
652 int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
653 int32_t pId = event.GetPointerId();
654 HILOG_DEBUG("pointer num is %{public}d, down pointer size is %{public}d, pointId is %{public}d", pIdSize,
655 downPointSize, pId);
656
657 MMI::PointerEvent::PointerItem pointerIterm;
658 if (!event.GetPointerItem(pId, pointerIterm)) {
659 HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
660 return;
661 }
662
663 MMI::PointerEvent::PointerItem basePointerIterm;
664 if (isMoveGestureRecognizing) {
665 if (!GetBasePointItem(basePointerIterm, pId, preGesturePoint_)) {
666 return;
667 }
668 } else {
669 if (!GetBasePointItem(basePointerIterm, pId, currentDownPoint_)) {
670 return;
671 }
672 }
673
674 int32_t offsetX = pointerIterm.GetDisplayX() - basePointerIterm.GetDisplayX();
675 int32_t offsetY = pointerIterm.GetDisplayY() - basePointerIterm.GetDisplayY();
676 HILOG_DEBUG("current point and first down point: pid %{public}d, %{public}d, %{public}d, %{public}d, %{public}d",
677 pId, pointerIterm.GetDisplayX(), pointerIterm.GetDisplayY(), basePointerIterm.GetDisplayX(),
678 basePointerIterm.GetDisplayY());
679
680 // two finger move will cancel gesture, but three or four finger move will enter move gesture recognize
681 if (!isMoveGestureRecognizing && hypot(offsetX, offsetY) > TOUCH_SLOP * downPointSize) {
682 if (downPointSize == POINTER_COUNT_2) {
683 HILOG_DEBUG("cancel gesture because finger move");
684 CancelGesture(false);
685 } else {
686 CancelThreeFingerEvent();
687 CancelFourFingerEvent();
688 SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
689 }
690 } else if (isMoveGestureRecognizing && (abs(offsetX) >= mMinPixelsBetweenSamplesX_ ||
691 abs(offsetY) >= mMinPixelsBetweenSamplesY_)) {
692 SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
693 }
694 }
695
StoreUpPointInPointerRoute(MMI::PointerEvent & event)696 void AccessibilityMultiTapGestureRecognizer::StoreUpPointInPointerRoute(MMI::PointerEvent &event)
697 {
698 HILOG_DEBUG();
699
700 if (!isMoveGestureRecognizing || multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
701 return;
702 }
703
704 MMI::PointerEvent::PointerItem pointerIterm;
705 int32_t pId = event.GetPointerId();
706 if (!event.GetPointerItem(pId, pointerIterm)) {
707 HILOG_ERROR("get GetPointerItem(%{public}d) failed", pId);
708 return;
709 }
710
711 MMI::PointerEvent::PointerItem basePointerIterm;
712 if (!GetBasePointItem(basePointerIterm, pId, preGesturePoint_)) {
713 return;
714 }
715
716 int32_t offsetX = pointerIterm.GetDisplayX() - basePointerIterm.GetDisplayX();
717 int32_t offsetY = pointerIterm.GetDisplayY() - basePointerIterm.GetDisplayY();
718 if (abs(offsetX) > mMinPixelsBetweenSamplesX_ || abs(offsetY) > mMinPixelsBetweenSamplesY_) {
719 SaveMoveGesturePointerInfo(event, pId, pointerIterm, offsetX, offsetY);
720 }
721 }
722
recognizeGesturePath(const std::vector<Pointer> & path)723 bool AccessibilityMultiTapGestureRecognizer::recognizeGesturePath(const std::vector<Pointer> &path)
724 {
725 HILOG_DEBUG();
726 if (path.size() < MIN_MOVE_POINTER_NUM) {
727 return false;
728 }
729
730 int pathSize = static_cast<int>(path.size() - 1);
731 for (int routerIndex = 0; routerIndex < pathSize; routerIndex++) {
732 int32_t dx = static_cast<int32_t>(path[routerIndex + 1].px_ - path[routerIndex].px_);
733 int32_t dy = static_cast<int32_t>(path[routerIndex + 1].py_ - path[routerIndex].py_);
734 if (GetSwipeDirection(dx, dy) != moveDirection) {
735 return false;
736 }
737 }
738 return true;
739 }
740
GetMoveGestureId()741 GestureType AccessibilityMultiTapGestureRecognizer::GetMoveGestureId()
742 {
743 HILOG_DEBUG();
744
745 int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
746 if (downPointSize == POINTER_COUNT_3) {
747 switch (moveDirection) {
748 case MoveGirectionType::SWIPE_LEFT:
749 return GestureType::GESTURE_THREE_FINGER_SWIPE_LEFT;
750 case MoveGirectionType::SWIPE_RIGHT:
751 return GestureType::GESTURE_THREE_FINGER_SWIPE_RIGHT;
752 case MoveGirectionType::SWIPE_UP:
753 return GestureType::GESTURE_THREE_FINGER_SWIPE_UP;
754 case MoveGirectionType::SWIPE_DOWN:
755 return GestureType::GESTURE_THREE_FINGER_SWIPE_DOWN;
756 default:
757 return GestureType::GESTURE_INVALID;
758 }
759 } else if (downPointSize == POINTER_COUNT_4) {
760 switch (moveDirection) {
761 case MoveGirectionType::SWIPE_LEFT:
762 return GestureType::GESTURE_FOUR_FINGER_SWIPE_LEFT;
763 case MoveGirectionType::SWIPE_RIGHT:
764 return GestureType::GESTURE_FOUR_FINGER_SWIPE_RIGHT;
765 case MoveGirectionType::SWIPE_UP:
766 return GestureType::GESTURE_FOUR_FINGER_SWIPE_UP;
767 case MoveGirectionType::SWIPE_DOWN:
768 return GestureType::GESTURE_FOUR_FINGER_SWIPE_DOWN;
769 default:
770 return GestureType::GESTURE_INVALID;
771 }
772 }
773 return GestureType::GESTURE_INVALID;
774 }
775
IsMoveGestureRecognize()776 bool AccessibilityMultiTapGestureRecognizer::IsMoveGestureRecognize()
777 {
778 HILOG_DEBUG();
779
780 if (!isMoveGestureRecognizing || multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
781 return false;
782 }
783
784 int32_t downPointSize = static_cast<int32_t>(currentDownPoint_.size());
785 if (static_cast<int32_t>(pointerRoute_.size()) != downPointSize) {
786 return false;
787 }
788
789 for (int32_t pIndex = 0; pIndex < downPointSize; pIndex++) {
790 if (pointerRoute_.count(pIndex) == 0 || pointerRoute_[pIndex].size() < MIN_MOVE_POINTER_NUM) {
791 return false;
792 }
793 if (!recognizeGesturePath(pointerRoute_[pIndex])) {
794 return false;
795 }
796 }
797
798 GestureType gestureId = GetMoveGestureId();
799 listener_->MultiFingerGestureOnCompleted(gestureId);
800
801 return true;
802 }
803
HandleMultiFingerTouchUpEvent(MMI::PointerEvent & event)804 void AccessibilityMultiTapGestureRecognizer::HandleMultiFingerTouchUpEvent(MMI::PointerEvent &event)
805 {
806 HILOG_DEBUG("gestureState is %{public}d, isFirstUp is %{public}d, target finger num is %{public}d",
807 multiFingerGestureState_, isFirstUp_, targetFingers_);
808
809 handler_->RemoveEvent(WAIT_ANOTHER_FINGER_DOWN_MSG);
810 CancelHoldGestureEvent();
811
812 if (multiFingerGestureState_ == MultiFingerGestureState::GESTURE_WAIT) {
813 handler_->SendEvent(CANCEL_WAIT_FINGER_DOWN_MSG, event.GetPointerIds().size(), DOUBLE_TAP_TIMEOUT / US_TO_MS);
814 }
815
816 StoreUpPointInPointerRoute(event);
817 if (event.GetPointerIds().size() == POINTER_COUNT_1) {
818 if (IsMoveGestureRecognize()) {
819 SetMultiFingerGestureState(MultiFingerGestureState::GESTURE_COMPLETE);
820 fingerTouchUpState_ = FingerTouchUpState::ALL_FINGER_TOUCH_UP;
821 Clear();
822 return;
823 }
824 fingerTouchUpState_ = FingerTouchUpState::ALL_FINGER_TOUCH_UP;
825 currentDownPoint_.clear();
826 preGesturePoint_.clear();
827 pointerRoute_.clear();
828 moveDirection = -1;
829 isMoveGestureRecognizing = false;
830 } else {
831 fingerTouchUpState_ = FingerTouchUpState::NOT_ALL_FINGER_TOUCH_UP;
832 }
833
834 if (isFirstUp_) {
835 isFirstUp_ = false;
836 if (targetFingers_ != -1 && static_cast<int32_t>(event.GetPointerIds().size()) != targetFingers_) {
837 CancelGesture(true);
838 return;
839 }
840 }
841
842 lastUpPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
843 if (targetFingers_ == -1 && multiFingerGestureState_ == MultiFingerGestureState::GESTURE_START) {
844 targetFingers_ = static_cast<int32_t>(event.GetPointerIds().size());
845 }
846 }
847
OnPointerEvent(MMI::PointerEvent & event)848 void AccessibilityMultiTapGestureRecognizer::OnPointerEvent(MMI::PointerEvent &event)
849 {
850 HILOG_DEBUG("gestureState is %{public}d", multiFingerGestureState_);
851
852 switch (event.GetPointerAction()) {
853 case MMI::PointerEvent::POINTER_ACTION_DOWN:
854 // cancel last cancel event when recevie a new down event
855 CancelAllPenddingEvent();
856 isFirstUp_ = true;
857 currentDownPoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
858 preGesturePoint_[event.GetPointerId()] = std::make_shared<MMI::PointerEvent>(event);
859 if (targetFingers_ == -1) {
860 HanleFirstTouchDownEvent(event);
861 } else {
862 HandleContinueTouchDownEvent(event);
863 }
864 break;
865 case MMI::PointerEvent::POINTER_ACTION_MOVE:
866 if (multiFingerGestureState_ != MultiFingerGestureState::GESTURE_START) {
867 return;
868 }
869 HandleMultiFingerMoveEvent(event);
870 break;
871 case MMI::PointerEvent::POINTER_ACTION_UP:
872 HandleMultiFingerTouchUpEvent(event);
873 break;
874 default:
875 break;
876 }
877 return;
878 }
879 } // namespace Accessibility
880 } // namespace OHOS
881