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