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