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