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 #ifndef EVENT_RESAMPLE_H
17 #define EVENT_RESAMPLE_H
18 
19 #include <vector>
20 #include <map>
21 #include <list>
22 
23 #include "proto.h"
24 #include "singleton.h"
25 #include "nocopyable.h"
26 #include "error_multimodal.h"
27 #include "pointer_event.h"
28 
29 namespace OHOS {
30 namespace MMI {
31 class EventResample final {
32     DECLARE_DELAYED_SINGLETON(EventResample);
33 
34 public:
35     DISALLOW_COPY_AND_MOVE(EventResample);
36     std::shared_ptr<PointerEvent> OnEventConsume(std::shared_ptr<PointerEvent> pointerEvent,
37                                                  int64_t frameTime, ErrCode &status);
38     std::shared_ptr<PointerEvent> GetPointerEvent();
39 
40     void PrintfDeviceName();
41 
42     // Microseconds per milliseconds.
43     static constexpr int64_t US_PER_MS = 1000;
44 
45     // Latency added during resampling.  A few milliseconds doesn't hurt much but
46     // reduces the impact of mispredicted touch positions.
47     static constexpr int64_t RESAMPLE_LATENCY = 5 * US_PER_MS;
48 
49     // Minimum time difference between consecutive samples before attempting to resample.
50     static constexpr int64_t RESAMPLE_MIN_DELTA = 2 * US_PER_MS;
51 
52     // Maximum time difference between consecutive samples before attempting to resample
53     // by extrapolation.
54     static constexpr int64_t RESAMPLE_MAX_DELTA = 20 * US_PER_MS;
55 
56     // Maximum time to predict forward from the last known state, to avoid predicting too
57     // far into the future.  This time is further bounded by 50% of the last time delta.
58     static constexpr int64_t RESAMPLE_MAX_PREDICTION = 4 * US_PER_MS;
59 
60     // Maximum history size to store samples
61     static constexpr size_t HISTORY_SIZE_MAX = 2;
62 
63 private:
64 
65     struct Pointer {
66         int32_t coordX;
67         int32_t coordY;
68         int32_t toolType;
69         int32_t id;
70 
CopyFromPointer71         void CopyFrom(const Pointer& other)
72         {
73             coordX = other.coordX;
74             coordY = other.coordY;
75             toolType = other.toolType;
76             id = other.id;
77         }
78 
ResetPointer79         void Reset()
80         {
81             coordX = 0;
82             coordY = 0;
83             toolType = 0;
84             id = 0;
85         }
86     };
87 
88     struct MotionEvent {
89         std::map<uint32_t, Pointer> pointers;
90         int64_t actionTime { 0 };
91         uint32_t pointerCount { 0 };
92         int32_t sourceType { PointerEvent::SOURCE_TYPE_UNKNOWN };
93         int32_t pointerAction { PointerEvent::POINTER_ACTION_UNKNOWN };
94         int32_t deviceId { 0 };
95         int32_t eventId { 0 };
96 
ResetMotionEvent97         void Reset()
98         {
99             pointers.clear();
100             actionTime = 0;
101             pointerCount = 0;
102             sourceType = PointerEvent::SOURCE_TYPE_UNKNOWN;
103             pointerAction = PointerEvent::POINTER_ACTION_UNKNOWN;
104             deviceId = 0;
105             eventId = 0;
106         }
107 
InitializeFromMotionEvent108         void InitializeFrom(MotionEvent& other)
109         {
110             for (auto &it : other.pointers) {
111                 pointers[it.first] = it.second;
112             }
113             actionTime = other.actionTime;
114             pointerCount = other.pointerCount;
115             deviceId = other.deviceId;
116             sourceType = other.sourceType;
117             pointerAction = other.pointerAction;
118             eventId = other.eventId;
119         }
120 
InitializeFromMotionEvent121         void InitializeFrom(std::shared_ptr<PointerEvent> event)
122         {
123             actionTime = event->GetActionTime();
124             deviceId = event->GetDeviceId();
125             sourceType = event->GetSourceType();
126             pointerAction = event->GetPointerAction();
127             eventId = event->GetId();
128 
129             std::vector<int32_t> pointerIds = event->GetPointerIds();
130             pointerCount = 0;
131             for (auto &it : pointerIds) {
132                 PointerEvent::PointerItem item;
133                 if (event->GetPointerItem(it, item)) {
134                     Pointer pointer;
135                     pointer.coordX = item.GetDisplayX();
136                     pointer.coordY = item.GetDisplayY();
137                     pointer.toolType = item.GetToolType();
138                     pointer.id = item.GetPointerId();
139                     pointers[pointer.id] = pointer;
140                     pointerCount++;
141                 }
142             }
143         }
144     };
145 
146     struct Batch {
147         std::vector<MotionEvent> samples;
148     };
149     std::vector<Batch> batches_;
150 
151     struct History {
152         std::map<uint32_t, Pointer> pointers;
153         int64_t actionTime { 0 };
154 
InitializeFromHistory155         void InitializeFrom(const MotionEvent &event)
156         {
157             actionTime = event.actionTime;
158             for (auto &it : event.pointers) {
159                 pointers[it.first] = it.second;
160             }
161         }
162 
InitializeFromHistory163         void InitializeFrom(const History &other)
164         {
165             actionTime = other.actionTime;
166             for (auto &it : other.pointers) {
167                 pointers[it.first] = it.second;
168             }
169         }
170 
GetPointerByIdHistory171         const Pointer& GetPointerById(uint32_t id) const
172         {
173             auto item = pointers.find(id);
174             return item->second;
175         }
176 
HasPointerIdHistory177         bool HasPointerId(uint32_t id) const
178         {
179             auto item = pointers.find(id);
180             if (item != pointers.end()) {
181                 return true;
182             } else {
183                 return false;
184             }
185         }
186     };
187 
188     struct TouchState {
189         int32_t deviceId;
190         int32_t source;
191         size_t historyCurrent;
192         size_t historySize;
193         History history[HISTORY_SIZE_MAX];
194         History lastResample;
195 
InitializeTouchState196         void Initialize(int32_t deviceId, int32_t source)
197         {
198             this->deviceId = deviceId;
199             this->source = source;
200             historyCurrent = 0;
201             historySize = 0;
202             lastResample.actionTime = 0;
203         }
204 
AddHistoryTouchState205         void AddHistory(const MotionEvent &event)
206         {
207             historyCurrent ^= 1;
208             if (historySize < HISTORY_SIZE_MAX) {
209                 historySize += 1;
210             }
211             history[historyCurrent].InitializeFrom(event);
212         }
213 
GetHistoryTouchState214         const History* GetHistory(size_t idx) const
215         {
216             return &history[(historyCurrent + idx) & 1];
217         }
218 
RecentCoordinatesAreIdenticalTouchState219         bool RecentCoordinatesAreIdentical(uint32_t id) const
220         {
221             // Return true if the two most recently received "raw" coordinates are identical
222             if (historySize < HISTORY_SIZE_MAX) {
223                 return false;
224             }
225             if (!GetHistory(0)->HasPointerId(id) || !GetHistory(1)->HasPointerId(id)) {
226                 return false;
227             }
228             float currentX = GetHistory(0)->GetPointerById(id).coordX;
229             float currentY = GetHistory(0)->GetPointerById(id).coordY;
230             float previousX = GetHistory(1)->GetPointerById(id).coordX;
231             float previousY = GetHistory(1)->GetPointerById(id).coordY;
232             if (currentX == previousX && currentY == previousY) {
233                 return true;
234             }
235             return false;
236         }
237     };
238     std::vector<TouchState> touchStates_;
239 
240     MotionEvent inputEvent_;
241     MotionEvent outputEvent_;
242     int64_t frameTime_ {-1};
243     bool resampleTouch_ {true};
244     std::shared_ptr<PointerEvent> pointerEvent_ {nullptr};
245 
246     void EventDump(const char *msg, MotionEvent &event);
247     ErrCode InitializeInputEvent(std::shared_ptr<PointerEvent> pointerEvent, int64_t frameTime);
248     bool UpdateBatch(MotionEvent** outEvent, ErrCode &result);
249     void UpdatePointerEvent(MotionEvent* outEvent);
250     ErrCode ConsumeBatch(int64_t frameTime, MotionEvent** outEvent);
251     ErrCode ConsumeSamples(Batch& batch, size_t count, MotionEvent** outEvent);
252     void AddSample(MotionEvent* outEvent, const MotionEvent* event);
253     void UpdateTouchState(MotionEvent &event);
254     void ResampleTouchState(int64_t sampleTime, MotionEvent* event, const MotionEvent* next);
255     void ResampleCoordinates(int64_t sampleTime, MotionEvent* event, TouchState &touchState,
256                              const History* current, const History* other, float alpha);
257     ssize_t FindBatch(int32_t deviceId, int32_t source) const;
258     ssize_t FindTouchState(int32_t deviceId, int32_t source) const;
259     bool CanAddSample(const Batch &batch, MotionEvent &event);
260     void RewriteMessage(TouchState& state, MotionEvent &event);
261     ssize_t FindSampleNoLaterThan(const Batch& batch, int64_t time);
262     bool ShouldResampleTool(int32_t toolType);
263     std::pair<int32_t, int32_t> TransformSampleWindowXY(std::shared_ptr<PointerEvent> pointerEvent,
264         PointerEvent::PointerItem &item, int32_t logicX, int32_t logicY);
265 };
266 
CalcCoord(float a,float b,float alpha)267 inline static float CalcCoord(float a, float b, float alpha)
268 {
269     return a + alpha * (b - a);
270 }
271 
272 #define EventResampleHdr ::OHOS::DelayedSingleton<EventResample>::GetInstance()
273 } // namespace MMI
274 } // namespace OHOS
275 #endif // EVENT_RESAMPLE_H
276