1 /*
2 * Copyright (c) 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 #undef LOG_TAG
17 #define LOG_TAG "InputEventSampler"
18
19 #include <chrono>
20 #include "input_event_transmission/input_event_sampler.h"
21 #include "devicestatus_define.h"
22
23 namespace OHOS {
24 namespace Msdp {
25 namespace DeviceStatus {
26 namespace Cooperate {
27
28 int32_t InputEventSampler::idealEventIntervalMS_ { 4 };
29 int32_t InputEventSampler::expiredIntervalMS_ { 24 };
30 int32_t InputEventSampler::rawDxThreshold_ { 20 };
31 int32_t InputEventSampler::rawDyThreshold_ { 20 };
32 std::unordered_set<int32_t> InputEventSampler::filterPointerActions_ {
33 MMI::PointerEvent::POINTER_ACTION_ENTER_WINDOW,
34 MMI::PointerEvent::POINTER_ACTION_LEAVE_WINDOW,
35 MMI::PointerEvent::POINTER_ACTION_PULL_IN_WINDOW,
36 MMI::PointerEvent::POINTER_ACTION_PULL_OUT_WINDOW,
37 };
38
InputEventSampler()39 InputEventSampler::InputEventSampler() { }
40
OnPointerEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)41 void InputEventSampler::OnPointerEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
42 {
43 if (IsSkipNeeded(pointerEvent)) {
44 return;
45 }
46 if (IsRawEventsExpired()) {
47 ClearRawEvents();
48 }
49 if (IsTouchPadEvent(pointerEvent)) {
50 HandleTouchPadEvent(pointerEvent);
51 } else {
52 HandleMouseEvent(pointerEvent);
53 }
54 OnDownSampledEvent();
55 }
56
SetPointerEventHandler(PointerEventHandler pointerEventHandler)57 void InputEventSampler::SetPointerEventHandler(PointerEventHandler pointerEventHandler)
58 {
59 pointerEventHandler_ = pointerEventHandler;
60 }
61
IsTouchPadEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)62 bool InputEventSampler::IsTouchPadEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
63 {
64 if (pointerEvent == nullptr) {
65 FI_HILOGW("Null pointerEvent, skip");
66 return false;
67 }
68 MMI::PointerEvent::PointerItem item;
69 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
70 FI_HILOGE("Corrupted pointerEvent, skip");
71 return false;
72 }
73 FI_HILOGD("Current toolType:%{public}d", item.GetToolType());
74 return (item.GetToolType() == MMI::PointerEvent::TOOL_TYPE_TOUCHPAD);
75 }
76
IsSpecialEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)77 bool InputEventSampler::IsSpecialEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
78 {
79 if (pointerEvent == nullptr) {
80 FI_HILOGW("Null pointerEvent, skip");
81 return false;
82 }
83 if (auto pointerAction = pointerEvent->GetPointerAction();
84 pointerAction != MMI::PointerEvent::POINTER_ACTION_MOVE &&
85 pointerAction != MMI::PointerEvent::POINTER_ACTION_PULL_MOVE) {
86 FI_HILOGI("Special event, action:%{public}d", pointerAction);
87 return true;
88 }
89 return false;
90 }
91
IsDurationMatched()92 bool InputEventSampler::IsDurationMatched()
93 {
94 std::lock_guard<std::mutex> guard(rawEventMutex_);
95 auto currentTimeStamp = std::chrono::steady_clock::now();
96 if (rawEvents_.empty()) {
97 return false;
98 }
99 auto headEvent = rawEvents_.front();
100 if (auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
101 currentTimeStamp - headEvent.rcvdTimeStamp).count(); duration >= idealEventIntervalMS_) {
102 FI_HILOGD("Current timeSpan:%{public}lld, matched condition", duration);
103 return true;
104 }
105 return false;
106 }
107
IsOffsetMatched(std::shared_ptr<MMI::PointerEvent> pointerEvent)108 bool InputEventSampler::IsOffsetMatched(std::shared_ptr<MMI::PointerEvent> pointerEvent)
109 {
110 MMI::PointerEvent::PointerItem item;
111 if (pointerEvent == nullptr) {
112 return false;
113 }
114 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
115 FI_HILOGE("Corrupted pointerEvent, skip");
116 return false;
117 }
118 auto rawDxSum = prefixRawDxSum_ + item.GetRawDx();
119 auto rawDySum = prefixRawDySum_ + item.GetRawDy();
120 if (abs(rawDxSum) >= rawDxThreshold_ || abs(rawDySum) >= rawDyThreshold_) {
121 FI_HILOGD("Current rawDxSum:%{public}d, rawDySum:%{public}d, match offset condition", rawDxSum, rawDySum);
122 return true;
123 }
124 return false;
125 }
126
IsRawEventsExpired()127 bool InputEventSampler::IsRawEventsExpired()
128 {
129 std::lock_guard<std::mutex> guard(rawEventMutex_);
130 if (rawEvents_.empty()) {
131 FI_HILOGD("Raw event expired,skip");
132 return false;
133 }
134 auto lastEvent = rawEvents_.back();
135 if (lastEvent.pointerEvent == nullptr) {
136 return false;
137 }
138 auto currentTimeStamp = std::chrono::steady_clock::now();
139 if (auto duration = std::chrono::duration_cast<std::chrono::milliseconds> (
140 currentTimeStamp - lastEvent.rcvdTimeStamp).count(); duration > expiredIntervalMS_) {
141 FI_HILOGD("Raw event expired, action:%{public}lld", duration);
142 return true;
143 }
144 return false;
145 }
146
IsSkipNeeded(std::shared_ptr<MMI::PointerEvent> pointerEvent)147 bool InputEventSampler::IsSkipNeeded(std::shared_ptr<MMI::PointerEvent> pointerEvent)
148 {
149 if (pointerEvent == nullptr) {
150 FI_HILOGW("Null pointerEvent, skip");
151 return true;
152 }
153 if (auto pointerAction = pointerEvent->GetPointerAction();
154 filterPointerActions_.find(pointerAction) != filterPointerActions_.end()) {
155 FI_HILOGI("Unexpected pointerEvent, action:%{public}d, skip", pointerAction);
156 return true;
157 }
158 return false;
159 }
160
AggregateRawEvents(std::shared_ptr<MMI::PointerEvent> pointerEvent)161 void InputEventSampler::AggregateRawEvents(std::shared_ptr<MMI::PointerEvent> pointerEvent)
162 {
163 MMI::PointerEvent::PointerItem item;
164 CHKPV(pointerEvent);
165 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
166 FI_HILOGW("Corrupted pointerEvent, skip");
167 return;
168 }
169 auto pointerId = item.GetPointerId();
170 auto sampledRawDx = prefixRawDxSum_ + item.GetRawDx();
171 auto sampledRawDy = prefixRawDySum_ + item.GetRawDy();
172
173 MMI::PointerEvent::PointerItem aggregatedItem = item;
174 aggregatedItem.SetRawDx(sampledRawDx);
175 aggregatedItem.SetRawDy(sampledRawDy);
176
177 pointerEvent->UpdatePointerItem(pointerId, aggregatedItem);
178 {
179 std::lock_guard<std::mutex> guard(sampledEventMutex_);
180 sampledEvents_.push(pointerEvent);
181 }
182 ClearRawEvents();
183 UpdateAggregationTimeStamp();
184 prefixRawDxSum_ = 0;
185 prefixRawDySum_ = 0;
186 }
187
HandleTouchPadEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)188 void InputEventSampler::HandleTouchPadEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
189 {
190 std::lock_guard<std::mutex> guard(sampledEventMutex_);
191 sampledEvents_.push(pointerEvent);
192 }
193
HandleMouseEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)194 void InputEventSampler::HandleMouseEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
195 {
196 CHKPV(pointerEvent);
197 if (IsSpecialEvent(pointerEvent) || IsAggregationIntervalMatched() || IsDurationMatched()) {
198 AggregateRawEvents(pointerEvent);
199 } else {
200 MMI::PointerEvent::PointerItem item;
201 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
202 FI_HILOGE("Corrupted pointerEvent, skip");
203 return;
204 }
205 prefixRawDxSum_ += item.GetRawDx();
206 prefixRawDySum_ += item.GetRawDy();
207 {
208 std::lock_guard<std::mutex> guard(rawEventMutex_);
209 rawEvents_.push({pointerEvent, std::chrono::steady_clock::now()});
210 FI_HILOGD("Raw events count:%{public}zu", rawEvents_.size());
211 }
212 }
213 }
214
OnDownSampledEvent()215 void InputEventSampler::OnDownSampledEvent()
216 {
217 std::lock_guard<std::mutex> guard(sampledEventMutex_);
218 FI_HILOGD("Sampled events existed count:%{public}zu", sampledEvents_.size());
219 while (!sampledEvents_.empty()) {
220 auto curEvent = sampledEvents_.front();
221 sampledEvents_.pop();
222 CHKPV(pointerEventHandler_);
223 pointerEventHandler_(curEvent);
224 }
225 }
226
ClearRawEvents()227 void InputEventSampler::ClearRawEvents()
228 {
229 std::lock_guard<std::mutex> guard(rawEventMutex_);
230 auto rawEvents = std::queue<RawEvent>();
231 rawEvents_ = rawEvents;
232 }
233
UpdateAggregationTimeStamp()234 void InputEventSampler::UpdateAggregationTimeStamp()
235 {
236 std::lock_guard<std::mutex> guard(aggregationTimeStampMutex_);
237 aggregationTimeStamp_ = std::chrono::steady_clock::now();
238 }
239
IsAggregationIntervalMatched()240 bool InputEventSampler::IsAggregationIntervalMatched()
241 {
242 std::lock_guard<std::mutex> guard(aggregationTimeStampMutex_);
243 if (auto duration = std::chrono::duration_cast<std::chrono::milliseconds> (
244 std::chrono::steady_clock::now() - aggregationTimeStamp_).count(); duration >= idealEventIntervalMS_) {
245 FI_HILOGD("Aggregation interval matched, duration:%{public}lld", duration);
246 return true;
247 }
248 return false;
249 }
250
251 } // namespace Cooperate
252 } // namespace DeviceStatus
253 } // namespace Msdp
254 } // namespace OHOS