1 /*
2 * Copyright (c) 2021-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 "core/components_ng/gestures/recognizers/click_recognizer.h"
17
18 #include "base/geometry/offset.h"
19 #include "base/log/log.h"
20 #include "base/ressched/ressched_report.h"
21 #include "base/utils/utils.h"
22 #include "core/components/common/layout/constants.h"
23 #include "core/components_ng/gestures/base_gesture_event.h"
24 #include "core/components_ng/gestures/gesture_referee.h"
25 #include "core/components_ng/gestures/recognizers/gesture_recognizer.h"
26 #include "core/components_ng/gestures/recognizers/multi_fingers_recognizer.h"
27 #include "core/pipeline_ng/pipeline_context.h"
28
29 namespace OHOS::Ace::NG {
30 namespace {
31
32 int32_t MULTI_FINGER_TIMEOUT = 300;
33 constexpr int32_t MULTI_FINGER_TIMEOUT_TOUCH = 300;
34 constexpr int32_t MULTI_FINGER_TIMEOUT_MOUSE = 300;
35 int32_t MULTI_TAP_TIMEOUT = 300;
36 constexpr int32_t MULTI_TAP_TIMEOUT_TOUCH = 300;
37 constexpr int32_t MULTI_TAP_TIMEOUT_MOUSE = 300;
38 constexpr int32_t MAX_THRESHOLD_MANYTAP = 60;
39 constexpr int32_t MAX_TAP_FINGERS = 10;
40 constexpr double MAX_THRESHOLD = 20.0;
41 constexpr int32_t DEFAULT_TAP_FINGERS = 1;
42 constexpr int32_t DEFAULT_LONGPRESS_DURATION = 800000000;
43
44 } // namespace
45
ForceCleanRecognizer()46 void ClickRecognizer::ForceCleanRecognizer()
47 {
48 MultiFingersRecognizer::ForceCleanRecognizer();
49 OnResetStatus();
50 }
51
IsPointInRegion(const TouchEvent & event)52 bool ClickRecognizer::IsPointInRegion(const TouchEvent& event)
53 {
54 if (distanceThreshold_ < std::numeric_limits<double>::infinity()) {
55 Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
56 if (offset.GetDistance() > distanceThreshold_) {
57 TAG_LOGI(AceLogTag::ACE_GESTURE, "Click move distance is larger than distanceThreshold_, "
58 "distanceThreshold_ is %{public}f", distanceThreshold_);
59 extraInfo_ += "move distance out of distanceThreshold.";
60 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
61 return false;
62 } else {
63 return true;
64 }
65 }
66 PointF localPoint(event.x, event.y);
67 auto frameNode = GetAttachedNode();
68 if (!frameNode.Invalid()) {
69 auto host = frameNode.Upgrade();
70 CHECK_NULL_RETURN(host, false);
71 NGGestureRecognizer::Transform(localPoint, frameNode, false, isPostEventResult_, event.postEventNodeId);
72 auto renderContext = host->GetRenderContext();
73 CHECK_NULL_RETURN(renderContext, false);
74 auto paintRect = renderContext->GetPaintRectWithoutTransform();
75 localPoint = localPoint + paintRect.GetOffset();
76 if (!host->InResponseRegionList(localPoint, responseRegionBuffer_)) {
77 TAG_LOGI(AceLogTag::ACE_GESTURE,
78 "InputTracking id:%{public}d, this MOVE/UP event is out of region, try to reject click gesture",
79 event.touchEventId);
80 extraInfo_ += "move/up event out of region.";
81 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
82 return false;
83 }
84 }
85 return true;
86 }
87
ClickRecognizer(int32_t fingers,int32_t count,double distanceThreshold)88 ClickRecognizer::ClickRecognizer(int32_t fingers, int32_t count, double distanceThreshold)
89 : MultiFingersRecognizer(fingers), count_(count), distanceThreshold_(distanceThreshold)
90 {
91 if (fingers_ > MAX_TAP_FINGERS || fingers_ < DEFAULT_TAP_FINGERS) {
92 fingers_ = DEFAULT_TAP_FINGERS;
93 }
94 if (distanceThreshold_ <= 0) {
95 distanceThreshold_ = std::numeric_limits<double>::infinity();
96 }
97 }
98
InitGlobalValue(SourceType sourceType)99 void ClickRecognizer::InitGlobalValue(SourceType sourceType)
100 {
101 switch (sourceType) {
102 case SourceType::TOUCH:
103 MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_TOUCH;
104 MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_TOUCH;
105 break;
106 case SourceType::MOUSE:
107 case SourceType::TOUCH_PAD:
108 MULTI_FINGER_TIMEOUT = MULTI_FINGER_TIMEOUT_MOUSE;
109 MULTI_TAP_TIMEOUT = MULTI_TAP_TIMEOUT_MOUSE;
110 break;
111 default:
112 break;
113 }
114 }
115
GetClickInfo()116 ClickInfo ClickRecognizer::GetClickInfo()
117 {
118 TouchEvent touchPoint = {};
119 if (!touchPoints_.empty()) {
120 touchPoint = touchPoints_.begin()->second;
121 }
122 ClickInfo info(touchPoint.id);
123 PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
124 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
125 isPostEventResult_, touchPoint.postEventNodeId);
126 Offset localOffset(localPoint.GetX(), localPoint.GetY());
127 info.SetTimeStamp(touchPoint.time);
128 info.SetScreenLocation(touchPoint.GetScreenOffset());
129 info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
130 info.SetSourceDevice(deviceType_);
131 info.SetDeviceId(deviceId_);
132 info.SetTarget(GetEventTarget().value_or(EventTarget()));
133 info.SetForce(touchPoint.force);
134 auto frameNode = GetAttachedNode().Upgrade();
135 std::string patternName = "";
136 if (frameNode) {
137 patternName = frameNode->GetTag();
138 }
139 info.SetPatternName(patternName.c_str());
140 if (touchPoint.tiltX.has_value()) {
141 info.SetTiltX(touchPoint.tiltX.value());
142 }
143 if (touchPoint.tiltY.has_value()) {
144 info.SetTiltY(touchPoint.tiltY.value());
145 }
146 info.SetSourceTool(touchPoint.sourceTool);
147 return info;
148 }
149
OnAccepted()150 void ClickRecognizer::OnAccepted()
151 {
152 int64_t acceptTime = GetSysTimestamp();
153 int64_t inputTime = acceptTime;
154 if (firstInputTime_.has_value()) {
155 inputTime = static_cast<int64_t>(firstInputTime_.value().time_since_epoch().count());
156 }
157 if (SystemProperties::GetTraceInputEventEnabled()) {
158 ACE_SCOPED_TRACE("UserEvent InputTime:%lld AcceptTime:%lld InputType:ClickGesture",
159 static_cast<long long>(inputTime), static_cast<long long>(acceptTime));
160 }
161 firstInputTime_.reset();
162
163 auto node = GetAttachedNode().Upgrade();
164 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Click accepted, tag: %{public}s",
165 node ? node->GetTag().c_str() : "null");
166 if (onAccessibilityEventFunc_) {
167 onAccessibilityEventFunc_(AccessibilityEventType::CLICK);
168 }
169 refereeState_ = RefereeState::SUCCEED;
170 ResSchedReport::GetInstance().ResSchedDataReport("click");
171 if (backupTouchPointsForSucceedBlock_.has_value()) {
172 touchPoints_ = backupTouchPointsForSucceedBlock_.value();
173 backupTouchPointsForSucceedBlock_.reset();
174 }
175 TouchEvent touchPoint = {};
176 if (!touchPoints_.empty()) {
177 touchPoint = touchPoints_.begin()->second;
178 }
179 PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
180 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
181 isPostEventResult_, touchPoint.postEventNodeId);
182 Offset localOffset(localPoint.GetX(), localPoint.GetY());
183 if (onClick_) {
184 ClickInfo info = GetClickInfo();
185 onClick_(info);
186 }
187
188 if (remoteMessage_) {
189 ClickInfo info = GetClickInfo();
190 info.SetTimeStamp(touchPoint.time);
191 info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(localOffset);
192 remoteMessage_(info);
193 }
194 UpdateFingerListInfo();
195 SendCallbackMsg(onAction_);
196
197 int64_t overTime = GetSysTimestamp();
198 if (SystemProperties::GetTraceInputEventEnabled()) {
199 ACE_SCOPED_TRACE("UserEvent InputTime:%lld OverTime:%lld InputType:ClickGesture",
200 static_cast<long long>(inputTime), static_cast<long long>(overTime));
201 }
202 firstInputTime_.reset();
203 }
204
OnRejected()205 void ClickRecognizer::OnRejected()
206 {
207 SendRejectMsg();
208 refereeState_ = RefereeState::FAIL;
209 firstInputTime_.reset();
210 backupTouchPointsForSucceedBlock_.reset();
211 }
212
HandleTouchDownEvent(const TouchEvent & event)213 void ClickRecognizer::HandleTouchDownEvent(const TouchEvent& event)
214 {
215 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW,
216 "Id:%{public}d, click %{public}d down, ETF: %{public}d, CTP: %{public}d, state: %{public}d",
217 event.touchEventId, event.id, equalsToFingers_, currentTouchPointsNum_, refereeState_);
218 extraInfo_ = "ETF: " + std::to_string(equalsToFingers_) + " CFP: " + std::to_string(currentTouchPointsNum_);
219 if (!firstInputTime_.has_value()) {
220 firstInputTime_ = event.time;
221 }
222
223 auto pipeline = PipelineBase::GetCurrentContext();
224 if (pipeline && pipeline->IsFormRender()) {
225 touchDownTime_ = event.time;
226 }
227 if (IsRefereeFinished()) {
228 auto node = GetAttachedNode().Upgrade();
229 TAG_LOGI(AceLogTag::ACE_GESTURE,
230 "Click recognizer handle touch down event refereeState is %{public}d, node tag = %{public}s, id = "
231 SEC_PLD(%{public}s) ".",
232 refereeState_, node ? node->GetTag().c_str() : "null",
233 SEC_PARAM(node ? std::to_string(node->GetId()).c_str() : "invalid"));
234 return;
235 }
236 InitGlobalValue(event.sourceType);
237 if (!IsInAttachedNode(event, false)) {
238 Adjudicate(Claim(this), GestureDisposal::REJECT);
239 return;
240 }
241 // The last recognition sequence has been completed, reset the timer.
242 if (tappedCount_ > 0 && currentTouchPointsNum_ == 0) {
243 responseRegionBuffer_.clear();
244 tapDeadlineTimer_.Cancel();
245 }
246 if (currentTouchPointsNum_ == 0) {
247 auto frameNode = GetAttachedNode();
248 if (!frameNode.Invalid()) {
249 auto host = frameNode.Upgrade();
250 responseRegionBuffer_ = host->GetResponseRegionListForRecognizer(static_cast<int32_t>(event.sourceType));
251 }
252 }
253 if (fingersId_.find(event.id) == fingersId_.end()) {
254 fingersId_.insert(event.id);
255 ++currentTouchPointsNum_;
256 touchPoints_[event.id] = event;
257 }
258 UpdateFingerListInfo();
259 if (fingers_ > currentTouchPointsNum_) {
260 // waiting for multi-finger press
261 DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
262 } else {
263 // Turn off the multi-finger press deadline timer
264 fingerDeadlineTimer_.Cancel();
265 equalsToFingers_ = true;
266 if (ExceedSlop()) {
267 TAG_LOGW(AceLogTag::ACE_GESTURE, "Fail to detect multi finger tap due to offset is out of slop");
268 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
269 }
270 }
271 if (currentTouchPointsNum_ == fingers_) {
272 focusPoint_ = ComputeFocusPoint();
273 }
274 }
275
IsFormRenderClickRejected(const TouchEvent & event)276 bool ClickRecognizer::IsFormRenderClickRejected(const TouchEvent& event)
277 {
278 Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
279 if (event.time.time_since_epoch().count() - touchDownTime_.time_since_epoch().count() >
280 DEFAULT_LONGPRESS_DURATION || offset.GetDistance() > MAX_THRESHOLD) {
281 TAG_LOGI(AceLogTag::ACE_GESTURE, "reject click when up, offset is %{public}f",
282 static_cast<float>(offset.GetDistance()));
283 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
284 return true;
285 }
286 return false;
287 }
288
TriggerClickAccepted(const TouchEvent & event)289 void ClickRecognizer::TriggerClickAccepted(const TouchEvent& event)
290 {
291 TAG_LOGI(AceLogTag::ACE_GESTURE, "Click try accept");
292 time_ = event.time;
293 if (!useCatchMode_) {
294 OnAccepted();
295 return;
296 }
297 auto onGestureJudgeBeginResult = TriggerGestureJudgeCallback();
298 if (onGestureJudgeBeginResult == GestureJudgeResult::REJECT) {
299 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
300 return;
301 }
302 Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
303 }
304
HandleTouchUpEvent(const TouchEvent & event)305 void ClickRecognizer::HandleTouchUpEvent(const TouchEvent& event)
306 {
307 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d up, state: %{public}d", event.touchEventId,
308 event.id, refereeState_);
309 auto pipeline = PipelineBase::GetCurrentContext();
310 // In a card scenario, determine the interval between finger pressing and finger lifting. Delete this section of
311 // logic when the formal scenario is complete.
312 if (pipeline && pipeline->IsFormRender() && IsFormRenderClickRejected(event)) {
313 return;
314 }
315 if (IsRefereeFinished()) {
316 return;
317 }
318 InitGlobalValue(event.sourceType);
319 touchPoints_[event.id] = event;
320 UpdateFingerListInfo();
321 auto isUpInRegion = IsPointInRegion(event);
322 if (fingersId_.find(event.id) != fingersId_.end()) {
323 fingersId_.erase(event.id);
324 --currentTouchPointsNum_;
325 }
326 if (currentTouchPointsNum_ == 0) {
327 responseRegionBuffer_.clear();
328 }
329 bool fingersNumberSatisfied = equalsToFingers_;
330 // Check whether multi-finger taps are completed in count_ times
331 if (equalsToFingers_ && (currentTouchPointsNum_ == 0) && isUpInRegion) {
332 // Turn off the multi-finger lift deadline timer
333 fingerDeadlineTimer_.Cancel();
334 tappedCount_++;
335 if (tappedCount_ == count_) {
336 TriggerClickAccepted(event);
337 return;
338 }
339 equalsToFingers_ = false;
340 // waiting for multi-finger lift
341 DeadlineTimer(tapDeadlineTimer_, MULTI_TAP_TIMEOUT);
342 }
343 if (refereeState_ != RefereeState::PENDING && refereeState_ != RefereeState::FAIL) {
344 if (fingersNumberSatisfied) {
345 Adjudicate(AceType::Claim(this), GestureDisposal::PENDING);
346 } else {
347 extraInfo_ += "finger number not satisfied.";
348 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
349 }
350 }
351 if (currentTouchPointsNum_ < fingers_ && equalsToFingers_) {
352 DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
353 }
354 }
355
HandleTouchMoveEvent(const TouchEvent & event)356 void ClickRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
357 {
358 if (currentFingers_ < fingers_) {
359 return;
360 }
361 if (IsRefereeFinished()) {
362 return;
363 }
364 InitGlobalValue(event.sourceType);
365 // In form scenario, if move more than 20vp, reject click gesture.
366 // Remove form scenario when formal solution is completed.
367 auto pipeline = PipelineBase::GetCurrentContext();
368 if (pipeline && pipeline->IsFormRender()) {
369 Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
370 if (offset.GetDistance() > MAX_THRESHOLD) {
371 TAG_LOGI(AceLogTag::ACE_GESTURE, "This gesture is out of offset, try to reject it");
372 extraInfo_ += "offset is out of region.";
373 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
374 }
375 }
376 IsPointInRegion(event);
377 UpdateFingerListInfo();
378 }
379
HandleTouchCancelEvent(const TouchEvent & event)380 void ClickRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
381 {
382 TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d cancel", event.touchEventId, event.id);
383 extraInfo_ += "receive cancel event.";
384 if (IsRefereeFinished()) {
385 return;
386 }
387 InitGlobalValue(event.sourceType);
388 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
389 }
390
HandleOverdueDeadline()391 void ClickRecognizer::HandleOverdueDeadline()
392 {
393 if (currentTouchPointsNum_ < fingers_ || tappedCount_ < count_) {
394 Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
395 }
396 }
397
DeadlineTimer(CancelableCallback<void ()> & deadlineTimer,int32_t time)398 void ClickRecognizer::DeadlineTimer(CancelableCallback<void()>& deadlineTimer, int32_t time)
399 {
400 auto context = PipelineContext::GetCurrentContext();
401 CHECK_NULL_VOID(context);
402
403 auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
404 auto refPtr = weakPtr.Upgrade();
405 if (refPtr) {
406 refPtr->HandleOverdueDeadline();
407 }
408 };
409
410 deadlineTimer.Reset(callback);
411 auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
412 taskExecutor.PostDelayedTask(deadlineTimer, time, "ArkUIGestureClickDeadlineTimer");
413 }
414
ComputeFocusPoint()415 Offset ClickRecognizer::ComputeFocusPoint()
416 {
417 Offset sumOfPoints;
418 int32_t count = 0;
419 for (auto& element : touchPoints_) {
420 if (count >= fingers_) {
421 break;
422 }
423 sumOfPoints = sumOfPoints + element.second.GetOffset();
424 count++;
425 }
426 Offset focusPoint = sumOfPoints / count;
427 return focusPoint;
428 }
429
ExceedSlop()430 bool ClickRecognizer::ExceedSlop()
431 {
432 if (tappedCount_ > 0 && tappedCount_ < count_) {
433 Offset currentFocusPoint = ComputeFocusPoint();
434 Offset slop = currentFocusPoint - focusPoint_;
435 if (GreatOrEqual(PipelineBase::Px2VpWithCurrentDensity(slop.GetDistance()), MAX_THRESHOLD_MANYTAP)) {
436 return true;
437 }
438 }
439 return false;
440 }
441
GetGestureEventInfo()442 GestureEvent ClickRecognizer::GetGestureEventInfo()
443 {
444 GestureEvent info;
445 info.SetTimeStamp(time_);
446 info.SetFingerList(fingerList_);
447 TouchEvent touchPoint = {};
448 for (const auto& pointKeyVal : touchPoints_) {
449 auto pointVal = pointKeyVal.second;
450 if (pointVal.sourceType != SourceType::NONE) {
451 touchPoint = pointVal;
452 break;
453 }
454 }
455 PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
456 NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
457 isPostEventResult_, touchPoint.postEventNodeId);
458 info.SetTimeStamp(touchPoint.time);
459 info.SetScreenLocation(touchPoint.GetScreenOffset());
460 info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
461 info.SetSourceDevice(deviceType_);
462 info.SetDeviceId(deviceId_);
463 info.SetTarget(GetEventTarget().value_or(EventTarget()));
464 info.SetForce(touchPoint.force);
465 auto frameNode = GetAttachedNode().Upgrade();
466 std::string patternName = "";
467 if (frameNode) {
468 patternName = frameNode->GetTag();
469 }
470 info.SetPatternName(patternName.c_str());
471
472 if (touchPoint.tiltX.has_value()) {
473 info.SetTiltX(touchPoint.tiltX.value());
474 }
475 if (touchPoint.tiltY.has_value()) {
476 info.SetTiltY(touchPoint.tiltY.value());
477 }
478 info.SetSourceTool(touchPoint.sourceTool);
479 #ifdef SECURITY_COMPONENT_ENABLE
480 info.SetDisplayX(touchPoint.screenX);
481 info.SetDisplayY(touchPoint.screenY);
482 #endif
483 info.SetPointerEvent(lastPointEvent_);
484 info.SetPressedKeyCodes(touchPoint.pressedKeyCodes_);
485 info.SetInputEventType(inputEventType_);
486 return info;
487 }
488
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & onAction)489 void ClickRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& onAction)
490 {
491 if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
492 return;
493 }
494 if (onAction && *onAction) {
495 GestureEvent info = GetGestureEventInfo();
496 // onAction may be overwritten in its invoke so we copy it first
497 auto onActionFunction = *onAction;
498 onActionFunction(info);
499 }
500 }
501
TriggerGestureJudgeCallback()502 GestureJudgeResult ClickRecognizer::TriggerGestureJudgeCallback()
503 {
504 auto targetComponent = GetTargetComponent();
505 CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
506 auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
507 auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
508 if (!callback && !sysJudge_ && !gestureRecognizerJudgeFunc) {
509 return GestureJudgeResult::CONTINUE;
510 }
511 auto info = std::make_shared<TapGestureEvent>();
512 info->SetTimeStamp(time_);
513 info->SetDeviceId(deviceId_);
514 info->SetFingerList(fingerList_);
515 TouchEvent touchPoint = {};
516 if (!touchPoints_.empty()) {
517 touchPoint = touchPoints_.begin()->second;
518 }
519 info->SetSourceDevice(deviceType_);
520 info->SetTarget(GetEventTarget().value_or(EventTarget()));
521 info->SetForce(touchPoint.force);
522 if (gestureInfo_) {
523 gestureInfo_->SetInputEventType(inputEventType_);
524 }
525 if (touchPoint.tiltX.has_value()) {
526 info->SetTiltX(touchPoint.tiltX.value());
527 }
528 if (touchPoint.tiltY.has_value()) {
529 info->SetTiltY(touchPoint.tiltY.value());
530 }
531 info->SetSourceTool(touchPoint.sourceTool);
532 if (sysJudge_) {
533 return sysJudge_(gestureInfo_, info);
534 }
535 if (gestureRecognizerJudgeFunc) {
536 return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
537 }
538 return callback(gestureInfo_, info);
539 }
540
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)541 bool ClickRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
542 {
543 RefPtr<ClickRecognizer> curr = AceType::DynamicCast<ClickRecognizer>(recognizer);
544 if (!curr) {
545 ResetStatus();
546 return false;
547 }
548
549 if (curr->count_ != count_ || curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_ ||
550 curr->distanceThreshold_ != distanceThreshold_) {
551 ResetStatus();
552 return false;
553 }
554
555 onAction_ = std::move(curr->onAction_);
556 ReconcileGestureInfoFrom(recognizer);
557 return true;
558 }
559
Dump() const560 RefPtr<GestureSnapshot> ClickRecognizer::Dump() const
561 {
562 RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
563 std::stringstream oss;
564 oss << "count: " << count_ << ", "
565 << "fingers: " << fingers_ << ", "
566 << DumpGestureInfo();
567 info->customInfo = oss.str();
568 return info;
569 }
570
CreateGestureFromRecognizer() const571 RefPtr<Gesture> ClickRecognizer::CreateGestureFromRecognizer() const
572 {
573 return AceType::MakeRefPtr<TapGesture>(count_, fingers_, distanceThreshold_);
574 }
575
CleanRecognizerState()576 void ClickRecognizer::CleanRecognizerState()
577 {
578 if ((refereeState_ == RefereeState::SUCCEED ||
579 refereeState_ == RefereeState::FAIL ||
580 refereeState_ == RefereeState::DETECTING) &&
581 currentFingers_ == 0) {
582 tappedCount_ = 0;
583 refereeState_ = RefereeState::READY;
584 disposal_ = GestureDisposal::NONE;
585 }
586 }
587 } // namespace OHOS::Ace::NG
588