• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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,bool isLimitFingerCount)88 ClickRecognizer::ClickRecognizer(int32_t fingers, int32_t count, double distanceThreshold, bool isLimitFingerCount)
89     : MultiFingersRecognizer(fingers, isLimitFingerCount), 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     if (CheckLimitFinger()) {
303         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
304         return;
305     }
306     Adjudicate(AceType::Claim(this), GestureDisposal::ACCEPT);
307 }
308 
HandleTouchUpEvent(const TouchEvent & event)309 void ClickRecognizer::HandleTouchUpEvent(const TouchEvent& event)
310 {
311     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d up, state: %{public}d", event.touchEventId,
312         event.id, refereeState_);
313     if (fingersId_.find(event.id) != fingersId_.end()) {
314         fingersId_.erase(event.id);
315         --currentTouchPointsNum_;
316     }
317     auto pipeline = PipelineBase::GetCurrentContext();
318     // In a card scenario, determine the interval between finger pressing and finger lifting. Delete this section of
319     // logic when the formal scenario is complete.
320     if (pipeline && pipeline->IsFormRender() && IsFormRenderClickRejected(event)) {
321         return;
322     }
323     if (IsRefereeFinished()) {
324         return;
325     }
326     InitGlobalValue(event.sourceType);
327     touchPoints_[event.id] = event;
328     UpdateFingerListInfo();
329     auto isUpInRegion = IsPointInRegion(event);
330     if (currentTouchPointsNum_ == 0) {
331         responseRegionBuffer_.clear();
332     }
333     bool fingersNumberSatisfied = equalsToFingers_;
334     // Check whether multi-finger taps are completed in count_ times
335     if (equalsToFingers_ && (currentTouchPointsNum_ == 0) && isUpInRegion) {
336         // Turn off the multi-finger lift deadline timer
337         fingerDeadlineTimer_.Cancel();
338         tappedCount_++;
339         if (CheckLimitFinger()) {
340             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
341         }
342         if (tappedCount_ == count_) {
343             TriggerClickAccepted(event);
344             return;
345         }
346         equalsToFingers_ = false;
347         // waiting for multi-finger lift
348         DeadlineTimer(tapDeadlineTimer_, MULTI_TAP_TIMEOUT);
349     }
350     if (refereeState_ != RefereeState::PENDING && refereeState_ != RefereeState::FAIL) {
351         if (fingersNumberSatisfied) {
352             Adjudicate(AceType::Claim(this), GestureDisposal::PENDING);
353         } else {
354             extraInfo_ += "finger number not satisfied.";
355             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
356         }
357     }
358     if (currentTouchPointsNum_ < fingers_ && equalsToFingers_) {
359         DeadlineTimer(fingerDeadlineTimer_, MULTI_FINGER_TIMEOUT);
360     }
361 }
362 
HandleTouchMoveEvent(const TouchEvent & event)363 void ClickRecognizer::HandleTouchMoveEvent(const TouchEvent& event)
364 {
365     if (currentFingers_ < fingers_) {
366         return;
367     }
368     if (IsRefereeFinished()) {
369         return;
370     }
371     InitGlobalValue(event.sourceType);
372     // In form scenario, if move more than 20vp, reject click gesture.
373     // Remove form scenario when formal solution is completed.
374     auto pipeline = PipelineBase::GetCurrentContext();
375     if (pipeline && pipeline->IsFormRender()) {
376         Offset offset = event.GetScreenOffset() - touchPoints_[event.id].GetScreenOffset();
377         if (offset.GetDistance() > MAX_THRESHOLD) {
378             TAG_LOGI(AceLogTag::ACE_GESTURE, "This gesture is out of offset, try to reject it");
379             extraInfo_ += "offset is out of region.";
380             Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
381         }
382     }
383     IsPointInRegion(event);
384     UpdateFingerListInfo();
385 }
386 
HandleTouchCancelEvent(const TouchEvent & event)387 void ClickRecognizer::HandleTouchCancelEvent(const TouchEvent& event)
388 {
389     TAG_LOGI(AceLogTag::ACE_INPUTKEYFLOW, "Id:%{public}d, click %{public}d cancel", event.touchEventId, event.id);
390     extraInfo_ += "receive cancel event.";
391     if (IsRefereeFinished()) {
392         return;
393     }
394     InitGlobalValue(event.sourceType);
395     Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
396 }
397 
HandleOverdueDeadline()398 void ClickRecognizer::HandleOverdueDeadline()
399 {
400     if (currentTouchPointsNum_ < fingers_ || tappedCount_ < count_) {
401         Adjudicate(AceType::Claim(this), GestureDisposal::REJECT);
402     }
403 }
404 
DeadlineTimer(CancelableCallback<void ()> & deadlineTimer,int32_t time)405 void ClickRecognizer::DeadlineTimer(CancelableCallback<void()>& deadlineTimer, int32_t time)
406 {
407     auto context = PipelineContext::GetCurrentContext();
408     CHECK_NULL_VOID(context);
409 
410     auto&& callback = [weakPtr = AceType::WeakClaim(this)]() {
411         auto refPtr = weakPtr.Upgrade();
412         if (refPtr) {
413             refPtr->HandleOverdueDeadline();
414         }
415     };
416 
417     deadlineTimer.Reset(callback);
418     auto taskExecutor = SingleTaskExecutor::Make(context->GetTaskExecutor(), TaskExecutor::TaskType::UI);
419     taskExecutor.PostDelayedTask(deadlineTimer, time, "ArkUIGestureClickDeadlineTimer");
420 }
421 
ComputeFocusPoint()422 Offset ClickRecognizer::ComputeFocusPoint()
423 {
424     Offset sumOfPoints;
425     int32_t count = 0;
426     for (auto& element : touchPoints_) {
427         if (count >= fingers_) {
428             break;
429         }
430         sumOfPoints = sumOfPoints + element.second.GetOffset();
431         count++;
432     }
433     Offset focusPoint = sumOfPoints / count;
434     return focusPoint;
435 }
436 
ExceedSlop()437 bool ClickRecognizer::ExceedSlop()
438 {
439     if (tappedCount_ > 0 && tappedCount_ < count_) {
440         Offset currentFocusPoint = ComputeFocusPoint();
441         Offset slop = currentFocusPoint - focusPoint_;
442         if (GreatOrEqual(PipelineBase::Px2VpWithCurrentDensity(slop.GetDistance()), MAX_THRESHOLD_MANYTAP)) {
443             return true;
444         }
445     }
446     return false;
447 }
448 
GetGestureEventInfo()449 GestureEvent ClickRecognizer::GetGestureEventInfo()
450 {
451     GestureEvent info;
452     info.SetTimeStamp(time_);
453     info.SetFingerList(fingerList_);
454     TouchEvent touchPoint = {};
455     for (const auto& pointKeyVal : touchPoints_) {
456         auto pointVal = pointKeyVal.second;
457         if (pointVal.sourceType != SourceType::NONE) {
458             touchPoint = pointVal;
459             break;
460         }
461     }
462     PointF localPoint(touchPoint.GetOffset().GetX(), touchPoint.GetOffset().GetY());
463     NGGestureRecognizer::Transform(localPoint, GetAttachedNode(), false,
464         isPostEventResult_, touchPoint.postEventNodeId);
465     info.SetTimeStamp(touchPoint.time);
466     info.SetScreenLocation(touchPoint.GetScreenOffset());
467     info.SetGlobalLocation(touchPoint.GetOffset()).SetLocalLocation(Offset(localPoint.GetX(), localPoint.GetY()));
468     info.SetSourceDevice(deviceType_);
469     info.SetDeviceId(deviceId_);
470     info.SetTarget(GetEventTarget().value_or(EventTarget()));
471     info.SetForce(touchPoint.force);
472     auto frameNode = GetAttachedNode().Upgrade();
473     std::string patternName = "";
474     if (frameNode) {
475         patternName = frameNode->GetTag();
476     }
477     info.SetPatternName(patternName.c_str());
478 
479     if (touchPoint.tiltX.has_value()) {
480         info.SetTiltX(touchPoint.tiltX.value());
481     }
482     if (touchPoint.tiltY.has_value()) {
483         info.SetTiltY(touchPoint.tiltY.value());
484     }
485     info.SetSourceTool(touchPoint.sourceTool);
486 #ifdef SECURITY_COMPONENT_ENABLE
487     info.SetDisplayX(touchPoint.screenX);
488     info.SetDisplayY(touchPoint.screenY);
489 #endif
490     info.SetPointerEvent(lastPointEvent_);
491     info.SetPressedKeyCodes(touchPoint.pressedKeyCodes_);
492     info.SetInputEventType(inputEventType_);
493     return info;
494 }
495 
SendCallbackMsg(const std::unique_ptr<GestureEventFunc> & onAction)496 void ClickRecognizer::SendCallbackMsg(const std::unique_ptr<GestureEventFunc>& onAction)
497 {
498     if (gestureInfo_ && gestureInfo_->GetDisposeTag()) {
499         return;
500     }
501     if (onAction && *onAction) {
502         GestureEvent info = GetGestureEventInfo();
503         // onAction may be overwritten in its invoke so we copy it first
504         auto onActionFunction = *onAction;
505         onActionFunction(info);
506     }
507 }
508 
TriggerGestureJudgeCallback()509 GestureJudgeResult ClickRecognizer::TriggerGestureJudgeCallback()
510 {
511     auto targetComponent = GetTargetComponent();
512     CHECK_NULL_RETURN(targetComponent, GestureJudgeResult::CONTINUE);
513     auto gestureRecognizerJudgeFunc = targetComponent->GetOnGestureRecognizerJudgeBegin();
514     auto callback = targetComponent->GetOnGestureJudgeBeginCallback();
515     if (!callback && !sysJudge_ && !gestureRecognizerJudgeFunc) {
516         return GestureJudgeResult::CONTINUE;
517     }
518     auto info = std::make_shared<TapGestureEvent>();
519     info->SetTimeStamp(time_);
520     info->SetDeviceId(deviceId_);
521     info->SetFingerList(fingerList_);
522     TouchEvent touchPoint = {};
523     if (!touchPoints_.empty()) {
524         touchPoint = touchPoints_.begin()->second;
525     }
526     info->SetSourceDevice(deviceType_);
527     info->SetTarget(GetEventTarget().value_or(EventTarget()));
528     info->SetForce(touchPoint.force);
529     if (gestureInfo_) {
530         gestureInfo_->SetInputEventType(inputEventType_);
531     }
532     if (touchPoint.tiltX.has_value()) {
533         info->SetTiltX(touchPoint.tiltX.value());
534     }
535     if (touchPoint.tiltY.has_value()) {
536         info->SetTiltY(touchPoint.tiltY.value());
537     }
538     info->SetSourceTool(touchPoint.sourceTool);
539     if (sysJudge_) {
540         return sysJudge_(gestureInfo_, info);
541     }
542     if (gestureRecognizerJudgeFunc) {
543         return gestureRecognizerJudgeFunc(info, Claim(this), responseLinkRecognizer_);
544     }
545     return callback(gestureInfo_, info);
546 }
547 
ReconcileFrom(const RefPtr<NGGestureRecognizer> & recognizer)548 bool ClickRecognizer::ReconcileFrom(const RefPtr<NGGestureRecognizer>& recognizer)
549 {
550     RefPtr<ClickRecognizer> curr = AceType::DynamicCast<ClickRecognizer>(recognizer);
551     if (!curr) {
552         ResetStatus();
553         return false;
554     }
555 
556     if (curr->count_ != count_ || curr->fingers_ != fingers_ || curr->priorityMask_ != priorityMask_ ||
557         curr->distanceThreshold_ != distanceThreshold_) {
558         ResetStatus();
559         return false;
560     }
561 
562     onAction_ = std::move(curr->onAction_);
563     ReconcileGestureInfoFrom(recognizer);
564     return true;
565 }
566 
Dump() const567 RefPtr<GestureSnapshot> ClickRecognizer::Dump() const
568 {
569     RefPtr<GestureSnapshot> info = NGGestureRecognizer::Dump();
570     std::stringstream oss;
571     oss << "count: " << count_ << ", "
572         << "fingers: " << fingers_ << ", "
573         << DumpGestureInfo();
574     info->customInfo = oss.str();
575     return info;
576 }
577 
CreateGestureFromRecognizer() const578 RefPtr<Gesture> ClickRecognizer::CreateGestureFromRecognizer() const
579 {
580     return AceType::MakeRefPtr<TapGesture>(count_, fingers_, distanceThreshold_, isLimitFingerCount_);
581 }
582 
CleanRecognizerState()583 void ClickRecognizer::CleanRecognizerState()
584 {
585     if ((refereeState_ == RefereeState::SUCCEED ||
586         refereeState_ == RefereeState::FAIL ||
587         refereeState_ == RefereeState::DETECTING) &&
588         currentFingers_ == 0) {
589         tappedCount_ = 0;
590         refereeState_ = RefereeState::READY;
591         disposal_ = GestureDisposal::NONE;
592     }
593 }
594 } // namespace OHOS::Ace::NG
595