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