• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 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 #include "event_resample.h"
17 
18 #include "event_log_helper.h"
19 #include "input_device_manager.h"
20 #include "i_input_windows_manager.h"
21 
22 #undef MMI_LOG_DOMAIN
23 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
24 #undef MMI_LOG_TAG
25 #define MMI_LOG_TAG "EventResample"
26 
27 namespace OHOS {
28 namespace MMI {
EventResample()29 EventResample::EventResample(){};
~EventResample()30 EventResample::~EventResample(){};
31 
OnEventConsume(std::shared_ptr<PointerEvent> pointerEvent,int64_t frameTime,ErrCode & status)32 std::shared_ptr<PointerEvent> EventResample::OnEventConsume(std::shared_ptr<PointerEvent> pointerEvent,
33                                                             int64_t frameTime, ErrCode &status)
34 {
35     CALL_DEBUG_ENTER;
36     MotionEvent* outEvent = nullptr;
37     ErrCode result = ERR_OK;
38 
39     status = ERR_OK;
40     if (ERR_OK != InitializeInputEvent(pointerEvent, frameTime)) {
41         status = ERR_WOULD_BLOCK;
42         return pointerEvent;
43     }
44 
45     do {
46         // All events are dispathed so consume batches
47         if (PointerEvent::POINTER_ACTION_UNKNOWN == inputEvent_.pointerAction) {
48             result = ConsumeBatch(frameTime_, &outEvent);
49             frameTime_ = 0;
50             if ((ERR_OK == result) && (nullptr != outEvent)) {
51                 status = result;
52                 break;
53             } else {
54                 status = result;
55                 return nullptr;
56             }
57         }
58 
59         // Add event into batch
60         if (UpdateBatch(&outEvent, result)) {
61             break;
62         }
63 
64         // Update touch state object
65         EventDump("UpdateTouchState", inputEvent_);
66         EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
67         PrintfDeviceName();
68         UpdateTouchState(inputEvent_);
69         return pointerEvent_;
70     } while (0);
71 
72     if ((ERR_OK == result) && (nullptr != outEvent)) {
73         // Update pointer event
74         UpdatePointerEvent(outEvent);
75         EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
76         PrintfDeviceName();
77         return pointerEvent_;
78     }
79 
80     return nullptr;
81 }
82 
GetPointerEvent()83 std::shared_ptr<PointerEvent> EventResample::GetPointerEvent()
84 {
85     return pointerEvent_;
86 }
87 
EventDump(const char * msg,MotionEvent & event)88 void EventResample::EventDump(const char *msg, MotionEvent &event)
89 {
90     MMI_HILOGD("%{public}s: pointerAction:%{public}d, actionTime:%{public}" PRId64 ", pointerCount:%{public}d,"
91                "sourceType:%{public}d, deviceId:%{public}d, eventId:%{public}d",
92                msg, event.pointerAction, event.actionTime, event.pointerCount,
93                event.sourceType, event.deviceId, event.eventId);
94     for (auto &it : event.pointers) {
95         MMI_HILOGD("ID:%{public}d, coordX:%d, coordY:%d, toolType:%{public}d",
96             it.second.id, it.second.coordX, it.second.coordY, it.second.toolType);
97     }
98 }
99 
InitializeInputEvent(std::shared_ptr<PointerEvent> pointerEvent,int64_t frameTime)100 ErrCode EventResample::InitializeInputEvent(std::shared_ptr<PointerEvent> pointerEvent, int64_t frameTime)
101 {
102     int32_t pointerAction = PointerEvent::POINTER_ACTION_UNKNOWN;
103 
104     if (pointerEvent != nullptr) {
105         pointerEvent_ = pointerEvent;
106     }
107 
108     if (frameTime_ <= 0) {
109         if (0 != frameTime) {
110             frameTime_ = frameTime;
111         } else if (nullptr != pointerEvent) {
112             frameTime_ = GetSysClockTime();
113         } else {
114             frameTime_ = 0;
115         }
116     }
117 
118     // Check that event can be consumed and initialize motion event.
119     if (nullptr != pointerEvent) {
120         EventLogHelper::PrintEventData(pointerEvent_, MMI_LOG_HEADER);
121         PrintfDeviceName();
122         pointerAction = pointerEvent->GetPointerAction();
123         MMI_HILOGD("pointerAction:%{public}d, actionTime:%{public}" PRId64 " frameTime_:%{public}" PRId64,
124                    pointerAction, pointerEvent->GetActionTime(), frameTime_);
125         switch (pointerAction) {
126             case PointerEvent::POINTER_ACTION_DOWN:
127             case PointerEvent::POINTER_ACTION_MOVE:
128             case PointerEvent::POINTER_ACTION_UP:
129                 break;
130             default: {
131                 MotionEvent event;
132                 event.InitializeFrom(pointerEvent);
133                 UpdateTouchState(event);
134                 return ERR_WOULD_BLOCK;
135             }
136         }
137         inputEvent_.Reset();
138         inputEvent_.InitializeFrom(pointerEvent);
139 
140         EventDump("Input Event", inputEvent_);
141     } else {
142         inputEvent_.Reset();
143     }
144 
145     return ERR_OK;
146 }
147 
UpdateBatch(MotionEvent ** outEvent,ErrCode & result)148 bool EventResample::UpdateBatch(MotionEvent** outEvent, ErrCode &result)
149 {
150     ssize_t batchIndex = FindBatch(inputEvent_.deviceId, inputEvent_.sourceType);
151     if (batchIndex >= 0) {
152         Batch& batch = batches_.at(batchIndex);
153         if (CanAddSample(batch, inputEvent_)) {
154             batch.samples.push_back(inputEvent_);
155             MMI_HILOGD("Event added to batch, deviceId:%{public}d, sourceType:%{public}d, pointerAction:%{public}d",
156                        inputEvent_.deviceId, inputEvent_.sourceType, inputEvent_.pointerAction);
157             return true;
158         }
159     }
160 
161     // Start a new batch
162     if (PointerEvent::POINTER_ACTION_MOVE == inputEvent_.pointerAction) {
163         Batch batch;
164         batch.samples.push_back(inputEvent_);
165         batches_.push_back(std::move(batch));
166         return true;
167     }
168 
169     return false;
170 }
171 
UpdatePointerEvent(MotionEvent * outEvent)172 void EventResample::UpdatePointerEvent(MotionEvent* outEvent)
173 {
174     EventDump("Output Event", *outEvent);
175     CHKPV(pointerEvent_);
176     pointerEvent_->SetActionTime(outEvent->actionTime);
177     pointerEvent_->SetPointerAction(outEvent->pointerAction);
178     pointerEvent_->SetActionTime(outEvent->actionTime);
179     pointerEvent_->SetId(outEvent->eventId);
180 
181     for (auto &it : outEvent->pointers) {
182         PointerEvent::PointerItem item;
183         if (pointerEvent_->GetPointerItem(it.first, item)) {
184             int32_t toolWindowX = item.GetToolWindowX();
185             int32_t toolWindowY = item.GetToolWindowY();
186             if (EventLogHelper::IsBetaVersion() && !pointerEvent_->HasFlag(InputEvent::EVENT_FLAG_PRIVACY_MODE)) {
187                 MMI_HILOGD("Output event: toolWindowX:%{public}d, toolWindowY:%{public}d", toolWindowX, toolWindowY);
188             } else {
189                 MMI_HILOGD("Output event: toolWindowX:%d, toolWindowY:%d", toolWindowX, toolWindowY);
190             }
191             auto logicX = it.second.coordX;
192             auto logicY = it.second.coordY;
193             item.SetDisplayX(logicX);
194             item.SetDisplayY(logicY);
195 
196             auto windowXY = TransformSampleWindowXY(pointerEvent_, item, logicX, logicY);
197             item.SetWindowX(windowXY.first);
198             item.SetWindowY(windowXY.second);
199 
200             if (PointerEvent::POINTER_ACTION_MOVE == outEvent->pointerAction) {
201                 item.SetPressed(true);
202             } else if (PointerEvent::POINTER_ACTION_UP == outEvent->pointerAction) {
203                 item.SetPressed(false);
204             } else {
205                 MMI_HILOGD("Output event:Pointer action:%{public}d", outEvent->pointerAction);
206             }
207             pointerEvent_->UpdatePointerItem(it.first, item);
208         }
209     }
210 }
211 
TransformSampleWindowXY(std::shared_ptr<PointerEvent> pointerEvent,PointerEvent::PointerItem & item,int32_t logicX,int32_t logicY)212 std::pair<int32_t, int32_t> EventResample::TransformSampleWindowXY(std::shared_ptr<PointerEvent> pointerEvent,
213     PointerEvent::PointerItem &item, int32_t logicX, int32_t logicY)
214 {
215     CALL_DEBUG_ENTER;
216     if (pointerEvent == nullptr) {
217         return {logicX + item.GetToolWindowX(), logicY + item.GetToolWindowY()};
218     }
219     auto windows = WIN_MGR->GetWindowGroupInfoByDisplayId(pointerEvent->GetTargetDisplayId());
220     for (const auto &window : windows) {
221         if (pointerEvent->GetTargetWindowId() == window.id) {
222             if (window.transform.empty()) {
223                 return {logicX + item.GetToolWindowX(), logicY + item.GetToolWindowY()};
224             }
225             auto windowXY = WIN_MGR->TransformWindowXY(window, logicX, logicY);
226             auto windowX = static_cast<int32_t>(windowXY.first);
227             auto windowY = static_cast<int32_t>(windowXY.second);
228             return {windowX, windowY};
229         }
230     }
231     return {logicX, logicY};
232 }
233 
ConsumeBatch(int64_t frameTime,MotionEvent ** outEvent)234 ErrCode EventResample::ConsumeBatch(int64_t frameTime, MotionEvent** outEvent)
235 {
236     int32_t result = 0;
237     for (size_t i = batches_.size(); i > 0;) {
238         i--;
239         Batch& batch = batches_.at(i);
240         if (frameTime < 0) {
241             result = ConsumeSamples(batch, batch.samples.size(), outEvent);
242             batches_.erase(batches_.begin() + i);
243             return result;
244         }
245 
246         int64_t sampleTime = frameTime;
247         if (resampleTouch_) {
248             sampleTime -= RESAMPLE_LATENCY;
249         }
250         ssize_t split = FindSampleNoLaterThan(batch, sampleTime);
251         if (split < 0) {
252             continue;
253         }
254 
255         result = ConsumeSamples(batch, split + 1, outEvent);
256         const MotionEvent* next;
257         if (batch.samples.empty()) {
258             batches_.erase(batches_.begin() + i);
259             next = NULL;
260         } else {
261             next = &batch.samples.at(0);
262         }
263         if (!result && resampleTouch_) {
264             ResampleTouchState(sampleTime, static_cast<MotionEvent*>(*outEvent), next);
265         }
266         return result;
267     }
268 
269     return ERR_WOULD_BLOCK;
270 }
271 
ConsumeSamples(Batch & batch,size_t count,MotionEvent ** outEvent)272 ErrCode EventResample::ConsumeSamples(Batch& batch, size_t count, MotionEvent** outEvent)
273 {
274     outputEvent_.Reset();
275 
276     for (size_t i = 0; i < count; i++) {
277         MotionEvent& event = batch.samples.at(i);
278         UpdateTouchState(event);
279         if (i > 0) {
280             AddSample(&outputEvent_, &event);
281         } else {
282             outputEvent_.InitializeFrom(event);
283         }
284     }
285     batch.samples.erase(batch.samples.begin(), batch.samples.begin() + count);
286 
287     *outEvent = &outputEvent_;
288 
289     return ERR_OK;
290 }
291 
AddSample(MotionEvent * outEvent,const MotionEvent * event)292 void EventResample::AddSample(MotionEvent* outEvent, const MotionEvent* event)
293 {
294     outEvent->actionTime = event->actionTime;
295     for (auto &it : event->pointers) {
296         outEvent->pointers[it.first] = it.second;
297     }
298 }
299 
UpdateTouchState(MotionEvent & event)300 void EventResample::UpdateTouchState(MotionEvent &event)
301 {
302     int32_t deviceId = event.deviceId;
303     int32_t source = event.sourceType;
304 
305     switch (event.pointerAction) {
306         case PointerEvent::POINTER_ACTION_DOWN: {
307             ssize_t idx = FindTouchState(deviceId, source);
308             if (idx < 0) {
309                 TouchState newState;
310                 touchStates_.push_back(newState);
311                 idx = static_cast<ssize_t>(touchStates_.size()) - 1;
312             }
313             TouchState& touchState = touchStates_.at(idx);
314             touchState.Initialize(deviceId, source);
315             touchState.AddHistory(event);
316             break;
317         }
318         case PointerEvent::POINTER_ACTION_MOVE: {
319             ssize_t idx = FindTouchState(deviceId, source);
320             if (idx >= 0) {
321                 TouchState& touchState = touchStates_.at(idx);
322                 touchState.AddHistory(event);
323                 RewriteMessage(touchState, event);
324             }
325             break;
326         }
327         case PointerEvent::POINTER_ACTION_UP:
328         default: {
329             ssize_t idx = FindTouchState(deviceId, source);
330             if (idx >= 0) {
331                 TouchState& touchState = touchStates_.at(idx);
332                 RewriteMessage(touchState, event);
333                 touchStates_.erase(touchStates_.begin() + idx);
334             }
335             frameTime_ = 0;
336             idx = FindBatch(deviceId, source);
337             if (idx >= 0) {
338                 batches_.erase(batches_.begin() + idx);
339             }
340             break;
341         }
342     }
343 }
344 
ResampleTouchState(int64_t sampleTime,MotionEvent * event,const MotionEvent * next)345 void EventResample::ResampleTouchState(int64_t sampleTime, MotionEvent* event, const MotionEvent* next)
346 {
347     if (!resampleTouch_ || (PointerEvent::SOURCE_TYPE_TOUCHSCREEN != event->sourceType)
348                         || (PointerEvent::POINTER_ACTION_MOVE != event->pointerAction)) {
349         return;
350     }
351 
352     ssize_t idx = FindTouchState(event->deviceId, event->sourceType);
353     if (idx < 0) {
354         return;
355     }
356 
357     TouchState &touchState = touchStates_.at(idx);
358     if (touchState.historySize < 1) {
359         return;
360     }
361 
362     // Ensure that the current sample has all of the pointers that need to be reported.
363     const History* current = touchState.GetHistory(0);
364     for (auto &it : event->pointers) {
365         if (!current->HasPointerId(it.first)) {
366             return;
367         }
368     }
369 
370     // Find the data to use for resampling.
371     const History* other;
372     History future;
373     float alpha;
374     if (next) {
375         // Interpolate between current sample and future sample.
376         // So current->actionTime <= sampleTime <= future.actionTime.
377         future.InitializeFrom(*next);
378         other = &future;
379         int64_t delta = future.actionTime - current->actionTime;
380         if (delta < RESAMPLE_MIN_DELTA) {
381             return;
382         }
383         alpha = static_cast<float>(sampleTime - current->actionTime) / delta;
384     } else if (touchState.historySize >= HISTORY_SIZE_MAX) {
385         // Extrapolate future sample using current sample and past sample.
386         // So other->actionTime <= current->actionTime <= sampleTime.
387         other = touchState.GetHistory(1);
388         int64_t delta = current->actionTime - other->actionTime;
389         if (delta < RESAMPLE_MIN_DELTA) {
390             return;
391         } else if (delta > RESAMPLE_MAX_DELTA) {
392             return;
393         }
394         int64_t maxPredict = current->actionTime + std::min(delta / 2, RESAMPLE_MAX_PREDICTION);
395         if (sampleTime > maxPredict) {
396             sampleTime = maxPredict;
397         }
398         alpha = static_cast<float>(current->actionTime - sampleTime) / delta;
399     } else {
400         return;
401     }
402 
403     // Resample touch coordinates.
404     ResampleCoordinates(sampleTime, event, touchState, current, other, alpha);
405 }
406 
ResampleCoordinates(int64_t sampleTime,MotionEvent * event,TouchState & touchState,const History * current,const History * other,float alpha)407 void EventResample::ResampleCoordinates(int64_t sampleTime, MotionEvent* event, TouchState &touchState,
408                                         const History* current, const History* other, float alpha)
409 {
410     History oldLastResample;
411     oldLastResample.InitializeFrom(touchState.lastResample);
412     touchState.lastResample.actionTime = sampleTime;
413 
414     for (auto &it : event->pointers) {
415         uint32_t id = it.first;
416         if (oldLastResample.HasPointerId(id) && touchState.RecentCoordinatesAreIdentical(id)) {
417             auto lastItem = touchState.lastResample.pointers.find(id);
418             if (lastItem != touchState.lastResample.pointers.end()) {
419                 auto oldLastItem = oldLastResample.pointers.find(id);
420                 lastItem->second.CopyFrom(oldLastItem->second);
421             }
422             continue;
423         }
424 
425         Pointer resampledCoords;
426         const Pointer& currentCoords = current->GetPointerById(id);
427         resampledCoords.CopyFrom(currentCoords);
428         auto item = event->pointers.find(id);
429         if (item == event->pointers.end()) {
430             return;
431         }
432         if (other->HasPointerId(id) && ShouldResampleTool(item->second.toolType)) {
433             const Pointer& otherCoords = other->GetPointerById(id);
434             resampledCoords.coordX = CalcCoord(currentCoords.coordX, otherCoords.coordX, alpha);
435             resampledCoords.coordY = CalcCoord(currentCoords.coordY, otherCoords.coordY, alpha);
436         }
437         item->second.CopyFrom(resampledCoords);
438         event->actionTime = sampleTime;
439     }
440 }
441 
FindBatch(int32_t deviceId,int32_t source) const442 ssize_t EventResample::FindBatch(int32_t deviceId, int32_t source) const
443 {
444     ssize_t idx = 0;
445     for (auto it = batches_.begin(); it < batches_.end(); ++it, ++idx) {
446         const MotionEvent& head = it->samples.at(0);
447         if ((head.deviceId == deviceId) && (head.sourceType == source)) {
448             return idx;
449         }
450     }
451     return -1;
452 }
453 
FindTouchState(int32_t deviceId,int32_t source) const454 ssize_t EventResample::FindTouchState(int32_t deviceId, int32_t source) const
455 {
456     ssize_t idx = 0;
457     for (auto it = touchStates_.begin(); it < touchStates_.end(); ++it, ++idx) {
458         if ((it->deviceId == deviceId) && (it->source == source)) {
459             return idx;
460         }
461     }
462     return -1;
463 }
464 
CanAddSample(const Batch & batch,MotionEvent & event)465 bool EventResample::CanAddSample(const Batch &batch, MotionEvent &event)
466 {
467     const MotionEvent& head = batch.samples.at(0);
468     uint32_t pointerCount = event.pointerCount;
469     int32_t pointerAction = event.pointerAction;
470     if ((head.pointerCount != pointerCount) || (head.pointerAction != pointerAction)) {
471         return false;
472     }
473 
474     return true;
475 }
476 
RewriteMessage(TouchState & state,MotionEvent & event)477 void EventResample::RewriteMessage(TouchState& state, MotionEvent &event)
478 {
479     for (auto &it : event.pointers) {
480         uint32_t id = it.first;
481         if (state.lastResample.HasPointerId(id)) {
482             if ((event.actionTime < state.lastResample.actionTime) || state.RecentCoordinatesAreIdentical(id)) {
483                 Pointer& msgCoords = it.second;
484                 const Pointer& resampleCoords = state.lastResample.GetPointerById(id);
485                 msgCoords.CopyFrom(resampleCoords);
486             } else {
487                 state.lastResample.pointers.erase(id);
488             }
489         }
490     }
491 }
492 
FindSampleNoLaterThan(const Batch & batch,int64_t time)493 ssize_t EventResample::FindSampleNoLaterThan(const Batch& batch, int64_t time)
494 {
495     size_t numSamples = batch.samples.size();
496     size_t idx = 0;
497     while ((idx < numSamples) && (batch.samples.at(idx).actionTime <= time)) {
498         idx += 1;
499     }
500     return ssize_t(idx) - 1;
501 }
502 
ShouldResampleTool(int32_t toolType)503 bool EventResample::ShouldResampleTool(int32_t toolType)
504 {
505     switch (toolType) {
506         case PointerEvent::TOOL_TYPE_FINGER:
507         case PointerEvent::TOOL_TYPE_PEN:
508             return true;
509         default:
510             return false;
511     }
512 }
513 
PrintfDeviceName()514 void EventResample::PrintfDeviceName()
515 {
516     auto device = INPUT_DEV_MGR->GetInputDevice(pointerEvent_->GetDeviceId());
517     CHKPV(device);
518     MMI_HILOGI("InputTracking id:%{public}d event created by:%{public}s", pointerEvent_->GetId(),
519         device->GetName().c_str());
520 }
521 
522 } // namespace MMI
523 } // namespace OHOS
524