1 /*
2 * Copyright (c) 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 #include "input_event_transmission/input_event_builder.h"
17
18 #include "display_info.h"
19
20 #include "cooperate_context.h"
21 #include "cooperate_hisysevent.h"
22 #include "devicestatus_define.h"
23 #include "input_event_transmission/input_event_serialization.h"
24 #include "utility.h"
25 #include "kits/c/wifi_hid2d.h"
26 #include "res_sched_client.h"
27 #include "res_type.h"
28
29 #undef LOG_TAG
30 #define LOG_TAG "InputEventBuilder"
31
32 namespace OHOS {
33 namespace Msdp {
34 namespace DeviceStatus {
35 namespace Cooperate {
36 namespace {
37 constexpr size_t LOG_PERIOD { 10 };
38 constexpr int32_t DEFAULT_SCREEN_WIDTH { 512 };
39 constexpr double MIN_DAMPLING_COEFFICENT { 0.05 };
40 constexpr double MAX_DAMPLING_COEFFICENT { 1.5 };
41 constexpr double DEFAULT_DAMPLING_COEFFICIENT { 1.0 };
42 const std::string WIFI_INTERFACE_NAME { "chba0" };
43 const int32_t RESTORE_SCENE { 0 };
44 const int32_t FORBIDDEN_SCENE { 1 };
45 const int32_t UPPER_SCENE_FPS { 0 };
46 const int32_t UPPER_SCENE_BW { 0 };
47 const int32_t MODE_ENABLE { 0 };
48 const int32_t MODE_DISABLE { 1 };
49 const std::string LOW_LATENCY_KEY = "identity";
50 }
51
InputEventBuilder(IContext * env)52 InputEventBuilder::InputEventBuilder(IContext *env)
53 : env_(env)
54 {
55 observer_ = std::make_shared<DSoftbusObserver>(*this);
56 pointerEvent_ = MMI::PointerEvent::Create();
57 keyEvent_ = MMI::KeyEvent::Create();
58
59 for (size_t index = 0, cnt = damplingCoefficients_.size(); index < cnt; ++index) {
60 damplingCoefficients_[index] = DEFAULT_DAMPLING_COEFFICIENT;
61 }
62 }
63
~InputEventBuilder()64 InputEventBuilder::~InputEventBuilder()
65 {
66 Disable();
67 }
68
Enable(Context & context)69 void InputEventBuilder::Enable(Context &context)
70 {
71 CALL_INFO_TRACE;
72 if (enable_) {
73 return;
74 }
75 enable_ = true;
76 xDir_ = 0;
77 movement_ = 0;
78 freezing_ = (context.CooperateFlag() & COOPERATE_FLAG_FREEZE_CURSOR);
79 remoteNetworkId_ = context.Peer();
80 env_->GetDSoftbus().AddObserver(observer_);
81 Coordinate cursorPos = context.CursorPosition();
82 TurnOffChannelScan();
83 FI_HILOGI("Cursor transite in (%{private}d, %{private}d)", cursorPos.x, cursorPos.y);
84 if (!enable_) {
85 CooperateRadarInfo radarInfo {
86 .funcName = __FUNCTION__,
87 .bizState = static_cast<int32_t> (BizState::STATE_END),
88 .bizStage = static_cast<int32_t> (BizCooperateStage::STATE_INPUT_EVENT_BUILDER_ENABLE),
89 .stageRes = static_cast<int32_t> (BizCooperateStageRes::RES_FAIL),
90 .bizScene = static_cast<int32_t> (BizCooperateScene::SCENE_PASSIVE),
91 .errCode = static_cast<int32_t> (CooperateRadarErrCode::INPUT_EVENT_BUILDER_ENABLE_FAILED),
92 .hostName = "",
93 .localNetId = Utility::DFXRadarAnonymize(context.Local().c_str()),
94 .peerNetId = Utility::DFXRadarAnonymize(remoteNetworkId_.c_str())
95 };
96 CooperateRadar::ReportCooperateRadarInfo(radarInfo);
97 }
98 ExecuteInner();
99 }
100
Disable()101 void InputEventBuilder::Disable()
102 {
103 CALL_INFO_TRACE;
104 if (enable_) {
105 enable_ = false;
106 env_->GetDSoftbus().RemoveObserver(observer_);
107 TurnOnChannelScan();
108 ResetPressedEvents();
109 }
110 if ((pointerEventTimer_ >= 0)) {
111 env_->GetTimerManager().RemoveTimerAsync(pointerEventTimer_);
112 pointerEventTimer_ = -1;
113 }
114 HandleStopTimer();
115 }
116
Update(Context & context)117 void InputEventBuilder::Update(Context &context)
118 {
119 remoteNetworkId_ = context.Peer();
120 FI_HILOGI("Update peer to \'%{public}s\'", Utility::Anonymize(remoteNetworkId_).c_str());
121 }
122
Freeze()123 void InputEventBuilder::Freeze()
124 {
125 if (!enable_) {
126 return;
127 }
128 xDir_ = 0;
129 movement_ = 0;
130 freezing_ = true;
131 FI_HILOGI("Freeze remote input from '%{public}s'", Utility::Anonymize(remoteNetworkId_).c_str());
132 }
133
Thaw()134 void InputEventBuilder::Thaw()
135 {
136 if (!enable_) {
137 return;
138 }
139 freezing_ = false;
140 FI_HILOGI("Thaw remote input from '%{public}s'", Utility::Anonymize(remoteNetworkId_).c_str());
141 }
142
SetDamplingCoefficient(uint32_t direction,double coefficient)143 void InputEventBuilder::SetDamplingCoefficient(uint32_t direction, double coefficient)
144 {
145 coefficient = std::clamp(coefficient, MIN_DAMPLING_COEFFICENT, MAX_DAMPLING_COEFFICENT);
146 FI_HILOGI("SetDamplingCoefficient(0x%{public}x, %{public}.3f)", direction, coefficient);
147 if ((direction & COORDINATION_DAMPLING_UP) == COORDINATION_DAMPLING_UP) {
148 damplingCoefficients_[DamplingDirection::DAMPLING_DIRECTION_UP] = coefficient;
149 }
150 if ((direction & COORDINATION_DAMPLING_DOWN) == COORDINATION_DAMPLING_DOWN) {
151 damplingCoefficients_[DamplingDirection::DAMPLING_DIRECTION_DOWN] = coefficient;
152 }
153 if ((direction & COORDINATION_DAMPLING_LEFT) == COORDINATION_DAMPLING_LEFT) {
154 damplingCoefficients_[DamplingDirection::DAMPLING_DIRECTION_LEFT] = coefficient;
155 }
156 if ((direction & COORDINATION_DAMPLING_RIGHT) == COORDINATION_DAMPLING_RIGHT) {
157 damplingCoefficients_[DamplingDirection::DAMPLING_DIRECTION_RIGHT] = coefficient;
158 }
159 }
160
UpdateVirtualDeviceIdMap(const std::unordered_map<int32_t,int32_t> & remote2VirtualIds)161 void InputEventBuilder::UpdateVirtualDeviceIdMap(const std::unordered_map<int32_t, int32_t> &remote2VirtualIds)
162 {
163 CALL_INFO_TRACE;
164 std::unique_lock<std::shared_mutex> lock(lock_);
165 remote2VirtualIds_ = remote2VirtualIds;
166 for (const auto &elem: remote2VirtualIds_) {
167 FI_HILOGI("Remote:%{public}d -> virtual:%{public}d", elem.first, elem.second);
168 }
169 }
170
GetDamplingCoefficient(DamplingDirection direction) const171 double InputEventBuilder::GetDamplingCoefficient(DamplingDirection direction) const
172 {
173 if ((direction >= DamplingDirection::DAMPLING_DIRECTION_UP) &&
174 (direction < DamplingDirection::N_DAMPLING_DIRECTIONS)) {
175 return damplingCoefficients_[direction];
176 }
177 return DEFAULT_DAMPLING_COEFFICIENT;
178 }
179
OnPacket(const std::string & networkId,Msdp::NetPacket & packet)180 bool InputEventBuilder::OnPacket(const std::string &networkId, Msdp::NetPacket &packet)
181 {
182 if (networkId != remoteNetworkId_) {
183 FI_HILOGW("Unexpected packet from \'%{public}s\'", Utility::Anonymize(networkId).c_str());
184 return false;
185 }
186 switch (packet.GetMsgId()) {
187 case MessageId::DSOFTBUS_INPUT_POINTER_EVENT: {
188 OnPointerEvent(packet);
189 break;
190 }
191 case MessageId::DSOFTBUS_INPUT_KEY_EVENT: {
192 OnKeyEvent(packet);
193 break;
194 }
195 case MessageId::DSOFTBUS_HEART_BEAT_PACKET: {
196 FI_HILOGD("Heart beat received");
197 break;
198 }
199 default: {
200 FI_HILOGW("Unexpected message(%{public}d) from \'%{public}s\'",
201 static_cast<int32_t>(packet.GetMsgId()), Utility::Anonymize(networkId).c_str());
202 return false;
203 }
204 }
205 return true;
206 }
207
OnPointerEvent(Msdp::NetPacket & packet)208 void InputEventBuilder::OnPointerEvent(Msdp::NetPacket &packet)
209 {
210 CHKPV(pointerEvent_);
211 if (scanState_) {
212 TurnOffChannelScan();
213 }
214 if ((pointerEventTimer_ >= 0)) {
215 env_->GetTimerManager().RemoveTimerAsync(pointerEventTimer_);
216 pointerEventTimer_ = -1;
217 }
218 pointerEvent_->Reset();
219 int32_t ret = InputEventSerialization::Unmarshalling(packet, pointerEvent_);
220 if (ret != RET_OK) {
221 FI_HILOGE("Failed to deserialize pointer event");
222 return;
223 }
224 if (!UpdatePointerEvent(pointerEvent_)) {
225 return;
226 }
227 TagRemoteEvent(pointerEvent_);
228 OnNotifyCrossDrag(pointerEvent_);
229 FI_HILOGD("PointerEvent(No:%{public}d, Source:%{public}s, Action:%{public}s)",
230 pointerEvent_->GetId(), pointerEvent_->DumpSourceType(), pointerEvent_->DumpPointerAction());
231 if (IsActive(pointerEvent_)) {
232 env_->GetInput().SimulateInputEvent(pointerEvent_);
233 }
234 pointerEventTimer_ = env_->GetTimerManager().AddTimerAsync(POINTER_EVENT_TIMEOUT, REPEAT_ONCE, [this]() {
235 TurnOnChannelScan();
236 pointerEventTimer_ = -1;
237 });
238 }
239
OnNotifyCrossDrag(std::shared_ptr<MMI::PointerEvent> pointerEvent)240 void InputEventBuilder::OnNotifyCrossDrag(std::shared_ptr<MMI::PointerEvent> pointerEvent)
241 {
242 CHKPV(pointerEvent);
243 auto pointerAction = pointerEvent->GetPointerAction();
244 if (pointerAction == MMI::PointerEvent::POINTER_ACTION_PULL_IN_WINDOW ||
245 pointerAction == MMI::PointerEvent::POINTER_ACTION_PULL_OUT_WINDOW) {
246 FI_HILOGD("PointerAction:%{public}d, it's pressedButtons is empty, skip", pointerAction);
247 return;
248 }
249 auto pressedButtons = pointerEvent->GetPressedButtons();
250 bool isButtonDown = (pressedButtons.find(MMI::PointerEvent::MOUSE_BUTTON_LEFT) != pressedButtons.end());
251 FI_HILOGD("PointerAction:%{public}d, isPressed:%{public}s", pointerAction, isButtonDown ? "true" : "false");
252 CHKPV(env_);
253 env_->GetDragManager().NotifyCrossDrag(isButtonDown);
254 }
255
OnKeyEvent(Msdp::NetPacket & packet)256 void InputEventBuilder::OnKeyEvent(Msdp::NetPacket &packet)
257 {
258 CHKPV(keyEvent_);
259 keyEvent_->Reset();
260 int32_t ret = InputEventSerialization::NetPacketToKeyEvent(packet, keyEvent_);
261 if (ret != RET_OK) {
262 FI_HILOGE("Failed to deserialize key event");
263 return;
264 }
265 FI_HILOGD("KeyEvent(No:%{public}d,Key:%{private}d,Action:%{public}d)",
266 keyEvent_->GetId(), keyEvent_->GetKeyCode(), keyEvent_->GetKeyAction());
267 keyEvent_->AddFlag(MMI::InputEvent::EVENT_FLAG_SIMULATE);
268 env_->GetInput().SimulateInputEvent(keyEvent_);
269 }
270
TurnOffChannelScan()271 void InputEventBuilder::TurnOffChannelScan()
272 {
273 CALL_INFO_TRACE;
274 scanState_ = false;
275 if (SetWifiScene(FORBIDDEN_SCENE) != RET_OK) {
276 scanState_ = true;
277 FI_HILOGE("Forbidden scene failed");
278 }
279 }
280
ExecuteInner()281 void InputEventBuilder::ExecuteInner()
282 {
283 CALL_DEBUG_ENTER;
284 // to enable low latency mode: value = 0
285 OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(
286 OHOS::ResourceSchedule::ResType::RES_TYPE_NETWORK_LATENCY_REQUEST, MODE_ENABLE,
287 {{LOW_LATENCY_KEY, FI_PKG_NAME}});
288 }
289
HandleStopTimer()290 void InputEventBuilder::HandleStopTimer()
291 {
292 CALL_DEBUG_ENTER;
293 OHOS::ResourceSchedule::ResSchedClient::GetInstance().ReportData(
294 OHOS::ResourceSchedule::ResType::RES_TYPE_NETWORK_LATENCY_REQUEST, MODE_DISABLE,
295 {{LOW_LATENCY_KEY, FI_PKG_NAME}});
296 }
297
TurnOnChannelScan()298 void InputEventBuilder::TurnOnChannelScan()
299 {
300 CALL_INFO_TRACE;
301 scanState_ = true;
302 if (SetWifiScene(RESTORE_SCENE) != RET_OK) {
303 scanState_ = false;
304 FI_HILOGE("Restore scene failed");
305 }
306 }
307
SetWifiScene(unsigned int scene)308 int32_t InputEventBuilder::SetWifiScene(unsigned int scene)
309 {
310 CALL_DEBUG_ENTER;
311 Hid2dUpperScene upperScene;
312 upperScene.scene = scene;
313 upperScene.fps = UPPER_SCENE_FPS;
314 upperScene.bw = UPPER_SCENE_BW;
315 if (Hid2dSetUpperScene(WIFI_INTERFACE_NAME.c_str(), &upperScene) != RET_OK) {
316 FI_HILOGE("Set wifi scene failed");
317 return RET_ERR;
318 }
319 return RET_OK;
320 }
321
UpdatePointerEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)322 bool InputEventBuilder::UpdatePointerEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
323 {
324 if (pointerEvent->GetSourceType() != MMI::PointerEvent::SOURCE_TYPE_MOUSE) {
325 return true;
326 }
327 if (!DampPointerMotion(pointerEvent)) {
328 FI_HILOGE("DampPointerMotion fail");
329 return false;
330 }
331 pointerEvent->AddFlag(MMI::InputEvent::EVENT_FLAG_RAW_POINTER_MOVEMENT);
332 int64_t time = Utility::GetSysClockTime();
333 pointerEvent->SetActionTime(time);
334 pointerEvent->SetActionStartTime(time);
335 pointerEvent->SetTargetDisplayId(-1);
336 pointerEvent->SetTargetWindowId(-1);
337 pointerEvent->SetAgentWindowId(-1);
338 return true;
339 }
340
DampPointerMotion(std::shared_ptr<MMI::PointerEvent> pointerEvent)341 bool InputEventBuilder::DampPointerMotion(std::shared_ptr<MMI::PointerEvent> pointerEvent)
342 {
343 MMI::PointerEvent::PointerItem item;
344 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
345 FI_HILOGE("Corrupted pointer event");
346 return false;
347 }
348 // Dampling pointer movement.
349 // First transition will trigger special effect which would damp pointer movement. We want to
350 // damp pointer movement even further than that could be achieved by setting pointer speed.
351 // By scaling increment of pointer movement, we want to enlarge the range of pointer speed setting.
352 if (item.GetRawDx() > 0) {
353 double rawDxRight = rawDxRightRemainder_ + item.GetRawDx() * GetDamplingCoefficient(
354 DamplingDirection::DAMPLING_DIRECTION_RIGHT);
355 int32_t rawDxIntegerRight = static_cast<int32_t>(rawDxRight);
356 rawDxRightRemainder_ = rawDxRight - static_cast<double>(rawDxIntegerRight);
357 item.SetRawDx(rawDxIntegerRight);
358 } else if (item.GetRawDx() < 0) {
359 double rawDxLeft = rawDxLeftRemainder_ + item.GetRawDx() * GetDamplingCoefficient(
360 DamplingDirection::DAMPLING_DIRECTION_LEFT);
361 int32_t rawDxIntegerLeft = static_cast<int32_t>(rawDxLeft);
362 rawDxLeftRemainder_ = rawDxLeft - static_cast<double>(rawDxIntegerLeft);
363 item.SetRawDx(rawDxIntegerLeft);
364 }
365 if (item.GetRawDy() >= 0) {
366 item.SetRawDy(static_cast<int32_t>(
367 item.GetRawDy() * GetDamplingCoefficient(DamplingDirection::DAMPLING_DIRECTION_DOWN)));
368 } else {
369 item.SetRawDy(static_cast<int32_t>(
370 item.GetRawDy() * GetDamplingCoefficient(DamplingDirection::DAMPLING_DIRECTION_UP)));
371 }
372 pointerEvent->UpdatePointerItem(pointerEvent->GetPointerId(), item);
373 return true;
374 }
375
TagRemoteEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)376 void InputEventBuilder::TagRemoteEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent)
377 {
378 std::shared_lock<std::shared_mutex> lock(lock_);
379 if (auto deviceId = pointerEvent->GetDeviceId(); remote2VirtualIds_.find(deviceId) != remote2VirtualIds_.end()) {
380 pointerEvent->SetDeviceId(remote2VirtualIds_[deviceId]);
381 } else {
382 pointerEvent->SetDeviceId((deviceId >= 0) ? -(deviceId + 1) : deviceId);
383 }
384 }
385
IsActive(std::shared_ptr<MMI::PointerEvent> pointerEvent)386 bool InputEventBuilder::IsActive(std::shared_ptr<MMI::PointerEvent> pointerEvent)
387 {
388 if (!freezing_) {
389 return true;
390 }
391 if ((pointerEvent->GetSourceType() != MMI::PointerEvent::SOURCE_TYPE_MOUSE) ||
392 ((pointerEvent->GetPointerAction() != MMI::PointerEvent::POINTER_ACTION_MOVE) &&
393 (pointerEvent->GetPointerAction() != MMI::PointerEvent::POINTER_ACTION_PULL_MOVE))) {
394 return true;
395 }
396 MMI::PointerEvent::PointerItem item;
397 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), item)) {
398 FI_HILOGE("Corrupted pointer event");
399 return false;
400 }
401 movement_ += item.GetRawDx();
402 movement_ = std::clamp(movement_, -DEFAULT_SCREEN_WIDTH, DEFAULT_SCREEN_WIDTH);
403 if (xDir_ == 0) {
404 xDir_ = movement_;
405 }
406 if (((xDir_ > 0) && (movement_ <= 0)) || ((xDir_ < 0) && (movement_ >= 0))) {
407 return true;
408 }
409 if ((nDropped_++ % LOG_PERIOD) == 0) {
410 FI_HILOGI("Remote input from '%{public}s' is freezing", Utility::Anonymize(remoteNetworkId_).c_str());
411 }
412 return false;
413 }
414
ResetPressedEvents()415 void InputEventBuilder::ResetPressedEvents()
416 {
417 CHKPV(env_);
418 CHKPV(pointerEvent_);
419 if (auto pressedButtons = pointerEvent_->GetPressedButtons(); !pressedButtons.empty()) {
420 auto dragState = env_->GetDragManager().GetDragState();
421 for (auto buttonId : pressedButtons) {
422 if (dragState == DragState::START && buttonId == MMI::PointerEvent::MOUSE_BUTTON_LEFT) {
423 FI_HILOGI("Dragging with mouse_button_left down, skip");
424 continue;
425 }
426 pointerEvent_->SetButtonId(buttonId);
427 pointerEvent_->SetPointerAction(MMI::PointerEvent::POINTER_ACTION_BUTTON_UP);
428 env_->GetInput().SimulateInputEvent(pointerEvent_);
429 FI_HILOGI("Simulate button-up event, buttonId:%{public}d", buttonId);
430 }
431 pointerEvent_->Reset();
432 }
433 }
434 } // namespace Cooperate
435 } // namespace DeviceStatus
436 } // namespace Msdp
437 } // namespace OHOS
438