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