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