1 /*
2  * Copyright (c) 2022 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 #ifndef FOUNDATION_ACE_FRAMEWORKS_CORE_EVENT_AXIS_EVENT_H
17 #define FOUNDATION_ACE_FRAMEWORKS_CORE_EVENT_AXIS_EVENT_H
18 
19 #include <list>
20 #include <utility>
21 
22 #include "base/geometry/offset.h"
23 #include "base/memory/ace_type.h"
24 #include "core/event/ace_events.h"
25 #include "core/event/key_event.h"
26 
27 namespace OHOS::MMI {
28 class PointerEvent;
29 } // namespace OHOS::MMI
30 
31 namespace OHOS::Ace {
32 
33 constexpr double MOUSE_WHEEL_DEGREES = 15.0;
34 constexpr double DP_PER_LINE_DESKTOP = 40.0;
35 constexpr Dimension LINE_HEIGHT_DESKTOP = 21.0_vp;
36 constexpr int32_t LINE_NUMBER_DESKTOP = 3;
37 constexpr int32_t DP_PER_LINE_PHONE = 64;
38 constexpr int32_t LINE_NUMBER_PHONE = 1;
39 
40 enum class AxisDirection : int32_t {
41     NONE = 0,
42     UP = 1,
43     DOWN = 2,
44     LEFT = 4,
45     RIGHT = 8,
46     UP_LEFT = 5,
47     UP_RIGHT = 9,
48     DOWN_LEFT = 6,
49     DOWN_RIGHT = 10,
50 };
51 
52 enum class AxisAction : int32_t {
53     NONE = 0,
54     BEGIN,
55     UPDATE,
56     END,
57     CANCEL,
58 };
59 struct UIInputEvent {
60     virtual ~UIInputEvent() = default;
61     TimeStamp time;
62 };
63 
64 struct AxisEvent final : public UIInputEvent {
65     ~AxisEvent() = default;
66     int32_t id = 0;
67     float x = 0.0;
68     float y = 0.0;
69     float screenX = 0.0;
70     float screenY = 0.0;
71     double verticalAxis = 0.0;
72     double horizontalAxis = 0.0;
73     double pinchAxisScale = 0.0;
74     double rotateAxisAngle = 0.0;
75     bool isRotationEvent = false;
76     AxisAction action = AxisAction::NONE;
77     int64_t deviceId = 0;
78     SourceType sourceType = SourceType::NONE;
79     SourceTool sourceTool = SourceTool::UNKNOWN;
80     std::shared_ptr<MMI::PointerEvent> pointerEvent;
81     int32_t touchEventId = 0;
82     std::vector<KeyCode> pressedCodes;
83 
84     // Coordinates relative to the upper-left corner of the current component
85     float localX = 0.0;
86     float localY = 0.0;
87 
88     int32_t targetDisplayId = 0;
89     int32_t originalId = 0;
90     bool isInjected = false;
91 
AxisEventfinal92     AxisEvent() {}
93 
AxisEventfinal94     AxisEvent(int32_t id, float x, float y, float screenX, float screenY, double verticalAxis, double horizontalAxis,
95         double pinchAxisScale, double rotateAxisAngle, bool isRotationEvent, AxisAction action, TimeStamp timestamp,
96         int64_t deviceId, SourceType sourceType, SourceTool sourceTool, std::shared_ptr<MMI::PointerEvent> pointerEvent,
97         std::vector<KeyCode> pressedCodes, int32_t targetDisplayId, int32_t originalId, bool isInjected)
98         : id(id), x(x), y(y), screenX(screenX), screenY(screenY), verticalAxis(verticalAxis),
99           horizontalAxis(horizontalAxis), pinchAxisScale(pinchAxisScale), rotateAxisAngle(rotateAxisAngle),
100           isRotationEvent(isRotationEvent), action(action), deviceId(deviceId), sourceType(sourceType),
101           sourceTool(sourceTool), pointerEvent(std::move(pointerEvent)), pressedCodes(pressedCodes),
102           targetDisplayId(targetDisplayId), originalId(originalId), isInjected(isInjected)
103     {
104         time = timestamp;
105     }
106 
CreateScaleEventfinal107     AxisEvent CreateScaleEvent(float scale) const
108     {
109         if (NearZero(scale)) {
110             return { id, x, y, screenX, screenY, verticalAxis, horizontalAxis, pinchAxisScale, rotateAxisAngle,
111                 isRotationEvent, action, time, deviceId, sourceType, sourceTool, pointerEvent, pressedCodes,
112                 targetDisplayId, originalId, isInjected };
113         }
114         return { id, x / scale, y / scale, screenX / scale, screenY / scale, verticalAxis, horizontalAxis,
115             pinchAxisScale, rotateAxisAngle, isRotationEvent, action, time, deviceId, sourceType, sourceTool,
116             pointerEvent, pressedCodes, targetDisplayId, originalId, isInjected };
117     }
118 
GetOffsetfinal119     Offset GetOffset() const
120     {
121         return Offset(x, y);
122     }
123 
GetScreenOffsetfinal124     Offset GetScreenOffset() const
125     {
126         return Offset(screenX, screenY);
127     }
128 
GetDirectionfinal129     AxisDirection GetDirection() const
130     {
131         uint32_t verticalFlag = 0;
132         uint32_t horizontalFlag = 0;
133         if (LessNotEqual(verticalAxis, 0.0)) {
134             verticalFlag = static_cast<uint32_t>(AxisDirection::UP);
135         } else if (GreatNotEqual(verticalAxis, 0.0)) {
136             verticalFlag = static_cast<uint32_t>(AxisDirection::DOWN);
137         }
138         if (LessNotEqual(horizontalAxis, 0.0)) {
139             horizontalFlag = static_cast<uint32_t>(AxisDirection::LEFT);
140         } else if (GreatNotEqual(horizontalAxis, 0.0)) {
141             horizontalFlag = static_cast<uint32_t>(AxisDirection::RIGHT);
142         }
143         return static_cast<AxisDirection>(verticalFlag | horizontalFlag);
144     }
IsDirectionUpfinal145     static bool IsDirectionUp(AxisDirection direction)
146     {
147         return (static_cast<uint32_t>(direction) & static_cast<uint32_t>(AxisDirection::UP));
148     }
IsDirectionDownfinal149     static bool IsDirectionDown(AxisDirection direction)
150     {
151         return (static_cast<uint32_t>(direction) & static_cast<uint32_t>(AxisDirection::DOWN));
152     }
IsDirectionLeftfinal153     static bool IsDirectionLeft(AxisDirection direction)
154     {
155         return (static_cast<uint32_t>(direction) & static_cast<uint32_t>(AxisDirection::LEFT));
156     }
IsDirectionRightfinal157     static bool IsDirectionRight(AxisDirection direction)
158     {
159         return (static_cast<uint32_t>(direction) & static_cast<uint32_t>(AxisDirection::RIGHT));
160     }
161 
162     Offset ConvertToOffset(bool isShiftKeyPressed = false, bool hasDifferentDirectionGesture = false) const
163     {
164         Offset result;
165         if (sourceTool == SourceTool::MOUSE) {
166             // Axis event is made by mouse.
167             if (isShiftKeyPressed) {
168                 result = Offset(-verticalAxis, -horizontalAxis);
169             } else {
170                 if (hasDifferentDirectionGesture) {
171                     result = Offset(-horizontalAxis, -verticalAxis);
172                 } else {
173                     result = Offset(-verticalAxis, -verticalAxis);
174                 }
175             }
176             return result * (LINE_HEIGHT_DESKTOP / MOUSE_WHEEL_DEGREES).ConvertToPx();
177         }
178         // Axis event is made by others. Include touch-pad.
179         result = Offset(-horizontalAxis, -verticalAxis);
180         return result;
181     }
182 
183     // MMI has the different direction, need to check truth direction.
ConvertToSummationAxisValuefinal184     std::pair<float, float> ConvertToSummationAxisValue(const AxisEvent& event) const
185     {
186         return std::make_pair(event.horizontalAxis - horizontalAxis, event.verticalAxis - verticalAxis);
187     }
188 };
189 
190 class AxisInfo : public BaseEventInfo {
191     DECLARE_RELATIONSHIP_OF_CLASSES(AxisInfo, BaseEventInfo);
192 
193 public:
AxisInfo()194     AxisInfo() : BaseEventInfo("onAxis") {}
AxisInfo(const AxisEvent & event,const Offset & localLocation,const EventTarget & target)195     AxisInfo(const AxisEvent& event, const Offset& localLocation, const EventTarget& target) : BaseEventInfo("onAxis")
196     {
197         action_ = event.action;
198         verticalAxis_ = static_cast<float>(event.verticalAxis);
199         horizontalAxis_ = static_cast<float>(event.horizontalAxis);
200         pinchAxisScale_ = static_cast<float>(event.pinchAxisScale);
201         rotateAxisAngle_ = static_cast<float>(event.rotateAxisAngle);
202         isRotationEvent_ = event.isRotationEvent;
203         globalLocation_ = event.GetOffset();
204         localLocation_ = localLocation;
205         screenLocation_ = Offset();
206         SetTimeStamp(event.time);
207         SetDeviceId(event.deviceId);
208         SetSourceDevice(event.sourceType);
209         SetTarget(target);
210     }
211     ~AxisInfo() override = default;
212 
SetAction(AxisAction action)213     void SetAction(AxisAction action)
214     {
215         action_ = action;
216     }
217 
GetAction()218     AxisAction GetAction() const
219     {
220         return action_;
221     }
222 
SetVerticalAxis(float axis)223     void SetVerticalAxis(float axis)
224     {
225         verticalAxis_ = axis;
226     }
227 
GetVerticalAxis()228     float GetVerticalAxis() const
229     {
230         return verticalAxis_;
231     }
232 
SetHorizontalAxis(float axis)233     void SetHorizontalAxis(float axis)
234     {
235         horizontalAxis_ = axis;
236     }
237 
GetHorizontalAxis()238     float GetHorizontalAxis() const
239     {
240         return horizontalAxis_;
241     }
242 
SetPinchAxisScale(float scale)243     void SetPinchAxisScale(float scale)
244     {
245         pinchAxisScale_ = scale;
246     }
247 
GetPinchAxisScale()248     float GetPinchAxisScale() const
249     {
250         return pinchAxisScale_;
251     }
252 
SetRotateAxisAngle(float angle)253     void SetRotateAxisAngle(float angle)
254     {
255         rotateAxisAngle_ = angle;
256     }
257 
GetRotateAxisAngle()258     float GetRotateAxisAngle() const
259     {
260         return rotateAxisAngle_;
261     }
262 
SetIsRotationEvent(bool rotationFlag)263     void SetIsRotationEvent(bool rotationFlag)
264     {
265         isRotationEvent_ = rotationFlag;
266     }
267 
GetIsRotationEvent()268     bool GetIsRotationEvent() const
269     {
270         return isRotationEvent_;
271     }
272 
SetGlobalLocation(const Offset & globalLocation)273     AxisInfo& SetGlobalLocation(const Offset& globalLocation)
274     {
275         globalLocation_ = globalLocation;
276         return *this;
277     }
SetLocalLocation(const Offset & localLocation)278     AxisInfo& SetLocalLocation(const Offset& localLocation)
279     {
280         localLocation_ = localLocation;
281         return *this;
282     }
283 
SetScreenLocation(const Offset & screenLocation)284     AxisInfo& SetScreenLocation(const Offset& screenLocation)
285     {
286         screenLocation_ = screenLocation;
287         return *this;
288     }
289 
GetScreenLocation()290     const Offset& GetScreenLocation() const
291     {
292         return screenLocation_;
293     }
294 
GetLocalLocation()295     const Offset& GetLocalLocation() const
296     {
297         return localLocation_;
298     }
GetGlobalLocation()299     const Offset& GetGlobalLocation() const
300     {
301         return globalLocation_;
302     }
303 
ConvertToAxisEvent()304     AxisEvent ConvertToAxisEvent() const
305     {
306         AxisEvent axisEvent;
307         axisEvent.x = static_cast<float>(globalLocation_.GetX());
308         axisEvent.y = static_cast<float>(globalLocation_.GetY());
309         axisEvent.screenX = static_cast<float>(screenLocation_.GetX());
310         axisEvent.screenY = static_cast<float>(screenLocation_.GetY());
311         axisEvent.horizontalAxis = horizontalAxis_;
312         axisEvent.verticalAxis = verticalAxis_;
313         axisEvent.pinchAxisScale = pinchAxisScale_;
314         axisEvent.rotateAxisAngle = rotateAxisAngle_;
315         axisEvent.time = timeStamp_;
316         axisEvent.localX = static_cast<float>(localLocation_.GetX());
317         axisEvent.localY = static_cast<float>(localLocation_.GetY());
318         return axisEvent;
319     }
320 
321 private:
322     AxisAction action_ = AxisAction::NONE;
323     float verticalAxis_ = 0.0;
324     float horizontalAxis_ = 0.0;
325     float pinchAxisScale_ = 0.0;
326     float rotateAxisAngle_ = 0.0;
327     bool isRotationEvent_ = false;
328     // global position at which the touch point contacts the screen.
329     Offset globalLocation_;
330     // Different from global location, The local location refers to the location of the contact point relative to the
331     // current node which has the recognizer.
332     Offset localLocation_;
333     Offset screenLocation_;
334 };
335 
336 using OnAxisEventFunc = std::function<void(AxisInfo&)>;
337 using GetEventTargetImpl = std::function<std::optional<EventTarget>()>;
338 
339 class AxisEventTarget : public virtual AceType {
340     DECLARE_ACE_TYPE(AxisEventTarget, AceType);
341 
342 public:
343     AxisEventTarget() = default;
AxisEventTarget(std::string frameName)344     AxisEventTarget(std::string frameName) : frameName_(std::move(frameName)) {}
345     ~AxisEventTarget() override = default;
346 
SetOnAxisCallback(const OnAxisEventFunc & onAxisCallback)347     void SetOnAxisCallback(const OnAxisEventFunc& onAxisCallback)
348     {
349         onAxisCallback_ = onAxisCallback;
350     }
351 
SetCoordinateOffset(const NG::OffsetF & coordinateOffset)352     void SetCoordinateOffset(const NG::OffsetF& coordinateOffset)
353     {
354         coordinateOffset_ = coordinateOffset;
355     }
356 
SetGetEventTargetImpl(const GetEventTargetImpl & getEventTargetImpl)357     void SetGetEventTargetImpl(const GetEventTargetImpl& getEventTargetImpl)
358     {
359         getEventTargetImpl_ = getEventTargetImpl;
360     }
361 
GetEventTarget()362     std::optional<EventTarget> GetEventTarget() const
363     {
364         if (getEventTargetImpl_) {
365             return getEventTargetImpl_();
366         }
367         return std::nullopt;
368     }
369 
SetFrameName(const std::string & frameName)370     void SetFrameName(const std::string& frameName)
371     {
372         frameName_ = frameName;
373     }
374 
GetFrameName()375     std::string GetFrameName() const
376     {
377         return frameName_;
378     }
379 
HandleAxisEvent(const AxisEvent & event)380     bool HandleAxisEvent(const AxisEvent& event)
381     {
382         if (!onAxisCallback_) {
383             return false;
384         }
385         Offset localLocation = Offset(
386             event.GetOffset().GetX() - coordinateOffset_.GetX(), event.GetOffset().GetY() - coordinateOffset_.GetY());
387         AxisInfo info = AxisInfo(event, localLocation, GetEventTarget().value_or(EventTarget()));
388         info.SetScreenLocation(Offset(event.screenX, event.screenY));
389         onAxisCallback_(info);
390         return true;
391     }
392 
HandleEvent(const AxisEvent & event)393     virtual void HandleEvent(const AxisEvent& event) {}
394 
395 private:
396     OnAxisEventFunc onAxisCallback_;
397     NG::OffsetF coordinateOffset_;
398     GetEventTargetImpl getEventTargetImpl_;
399     std::string frameName_ = "Unknown";
400 };
401 
402 using AxisTestResult = std::list<RefPtr<AxisEventTarget>>;
403 
404 } // namespace OHOS::Ace
405 
406 #endif // FOUNDATION_ACE_FRAMEWORKS_CORE_EVENT_AXIS_EVENT_H