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 "virtual_mouse.h"
17 
18 #include <cmath>
19 
20 #include <linux/input.h>
21 
22 #include "display_manager.h"
23 #include "input_manager.h"
24 
25 #include "devicestatus_define.h"
26 #include "fi_log.h"
27 #include "virtual_device_defines.h"
28 #include "virtual_mouse_builder.h"
29 
30 #undef LOG_TAG
31 #define LOG_TAG "VirtualMouse"
32 
33 namespace OHOS {
34 namespace Msdp {
35 namespace DeviceStatus {
36 namespace {
37 constexpr int32_t REL_WHEEL_VALUE { 1 };
38 constexpr int32_t REL_WHEEL_HI_RES_VALUE { 120 };
39 constexpr int32_t MAX_SCROLL_LENGTH { 10 };
40 constexpr int32_t MINIMUM_INTERVAL { 8 };
41 constexpr double FAST_STEP { 5.0 };
42 constexpr double TWICE_FAST_STEP { 2.0 * FAST_STEP };
43 constexpr double MAXIMUM_STEP_LENGTH { 5000.0 };
44 constexpr double STEP_UNIT { 1.0 };
45 int32_t g_screenWidth { 720 };
46 int32_t g_screenHeight { 1280 };
47 } // namespace
48 
49 class PointerPositionMonitor final : public MMI::IInputEventConsumer {
50 public:
51     PointerPositionMonitor() = default;
52     ~PointerPositionMonitor() = default;
53 
OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const54     void OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const override {};
55     void OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const override;
OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const56     void OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const override {};
57 
GetCount() const58     size_t GetCount() const
59     {
60         return count_;
61     }
62 
GetX() const63     int32_t GetX() const
64     {
65         return pos_.x;
66     }
67 
GetY() const68     int32_t GetY() const
69     {
70         return pos_.y;
71     }
72 
73 private:
74     mutable size_t count_ { 0 };
75     mutable Coordinate pos_ {};
76 };
77 
OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const78 void PointerPositionMonitor::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const
79 {
80     CHKPV(pointerEvent);
81     if (pointerEvent->GetSourceType() != MMI::PointerEvent::SOURCE_TYPE_MOUSE) {
82         return;
83     }
84     MMI::PointerEvent::PointerItem pointerItem;
85     if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) {
86         FI_HILOGE("Pointer event is corrupt");
87         return;
88     }
89 
90     pos_.x = pointerItem.GetDisplayX();
91     pos_.y = pointerItem.GetDisplayY();
92     ++count_;
93 }
94 
95 std::shared_ptr<VirtualMouse> VirtualMouse::device_ = nullptr;
96 
GetDevice()97 std::shared_ptr<VirtualMouse> VirtualMouse::GetDevice()
98 {
99     if (device_ == nullptr) {
100         std::string node;
101         if (VirtualDevice::FindDeviceNode(VirtualMouseBuilder::GetDeviceName(), node)) {
102             auto vMouse = std::make_shared<VirtualMouse>(node);
103             CHKPP(vMouse);
104             if (vMouse->IsActive()) {
105                 device_ = vMouse;
106             }
107         }
108     }
109     return device_;
110 }
111 
VirtualMouse(const std::string & name)112 VirtualMouse::VirtualMouse(const std::string &name) : VirtualDevice(name)
113 {
114     VirtualDevice::SetMinimumInterval(MINIMUM_INTERVAL);
115 }
116 
DownButton(int32_t button)117 int32_t VirtualMouse::DownButton(int32_t button)
118 {
119     CALL_DEBUG_ENTER;
120     if (button < BTN_MOUSE || button > BTN_TASK) {
121         FI_HILOGE("Not mouse button:%{public}d", button);
122         return RET_ERR;
123     }
124 
125     SendEvent(EV_MSC, MSC_SCAN, OBFUSCATED);
126     SendEvent(EV_KEY, button, DOWN_VALUE);
127     SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
128     return RET_OK;
129 }
130 
UpButton(int32_t button)131 int32_t VirtualMouse::UpButton(int32_t button)
132 {
133     CALL_DEBUG_ENTER;
134     if (button < BTN_MOUSE || button > BTN_TASK) {
135         FI_HILOGE("Not mouse button:%{public}d", button);
136         return RET_ERR;
137     }
138 
139     SendEvent(EV_MSC, MSC_SCAN, OBFUSCATED);
140     SendEvent(EV_KEY, button, UP_VALUE);
141     SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
142     return RET_OK;
143 }
144 
Scroll(int32_t dy)145 void VirtualMouse::Scroll(int32_t dy)
146 {
147     CALL_DEBUG_ENTER;
148     int32_t wheelValue = REL_WHEEL_VALUE;
149     int32_t wheelHiResValue = REL_WHEEL_HI_RES_VALUE;
150 
151     if (dy < 0) {
152         wheelValue = -wheelValue;
153         wheelHiResValue = -wheelHiResValue;
154         dy = -dy;
155     }
156     if (dy > MAX_SCROLL_LENGTH) {
157         dy = MAX_SCROLL_LENGTH;
158     }
159     for (; dy >= REL_WHEEL_VALUE; dy -= REL_WHEEL_VALUE) {
160         SendEvent(EV_REL, REL_WHEEL, wheelValue);
161         SendEvent(EV_REL, REL_HWHEEL_HI_RES, wheelHiResValue);
162         SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
163     }
164 }
165 
Move(int32_t dx,int32_t dy)166 void VirtualMouse::Move(int32_t dx, int32_t dy)
167 {
168     CALL_DEBUG_ENTER;
169     double delta = ::hypot(dx, dy);
170     if (std::abs(delta) < STEP_UNIT) {
171         FI_HILOGE("Mouse not moving");
172         return;
173     }
174     double total = std::min(delta, MAXIMUM_STEP_LENGTH);
175     double step = FAST_STEP;
176     int32_t count = static_cast<int32_t>(ceil(total / FAST_STEP));
177     while (count-- > 0) {
178         if (total < TWICE_FAST_STEP) {
179             if (total > FAST_STEP) {
180                 step = total / HALF_VALUE;
181             } else {
182                 step = total;
183             }
184         } else {
185             step = FAST_STEP;
186         }
187         double tx = round(step * static_cast<double>(dx) / delta);
188         double ty = round(step * static_cast<double>(dy) / delta);
189 
190         if ((std::abs(tx) >= STEP_UNIT) && (std::abs(tx) <= MAXIMUM_STEP_LENGTH)) {
191             SendEvent(EV_REL, REL_X, static_cast<int32_t>(tx));
192         }
193         if ((std::abs(ty) >= STEP_UNIT) && (std::abs(ty) <= MAXIMUM_STEP_LENGTH)) {
194             SendEvent(EV_REL, REL_Y, static_cast<int32_t>(ty));
195         }
196         if (((std::abs(tx) >= STEP_UNIT) && (std::abs(tx) <= MAXIMUM_STEP_LENGTH)) ||
197             ((std::abs(ty) >= STEP_UNIT) && (std::abs(ty) <= MAXIMUM_STEP_LENGTH))) {
198             SendEvent(EV_SYN, SYN_REPORT, SYNC_VALUE);
199         }
200         total -= step;
201     }
202 }
203 
MoveTo(int32_t x,int32_t y)204 int32_t VirtualMouse::MoveTo(int32_t x, int32_t y)
205 {
206     CALL_DEBUG_ENTER;
207     MMI::InputManager *inputMgr = MMI::InputManager::GetInstance();
208     CHKPR(inputMgr, RET_ERR);
209     auto monitor = std::make_shared<PointerPositionMonitor>();
210     int32_t monitorId = inputMgr->AddMonitor(monitor);
211     if (monitorId < 0) {
212         return RET_ERR;
213     }
214     size_t count = monitor->GetCount();
215     int32_t nLoops = 5;
216     Move(MOVE_VALUE_X, MOVE_VALUE_Y);
217     int32_t ret = RET_OK;
218     while (nLoops-- > 0) {
219         int32_t nTries = 125;
220         for (;;) {
221             if (monitor->GetCount() > count) {
222                 count = monitor->GetCount();
223                 break;
224             }
225             if (--nTries < 0) {
226                 FI_HILOGE("No pointer motion detected");
227                 ret = RET_ERR;
228                 goto CLEANUP;
229             }
230             std::this_thread::sleep_for(std::chrono::milliseconds(MINIMUM_INTERVAL));
231         }
232         FI_HILOGD("Current position: (%{private}d, %{private}d)", monitor->GetX(), monitor->GetY());
233         if (x == monitor->GetX() && y == monitor->GetY()) {
234             ret = RET_OK;
235             goto CLEANUP;
236         }
237         Move(x - monitor->GetX(), y - monitor->GetY());
238     }
239 CLEANUP:
240     inputMgr->RemoveMonitor(monitorId);
241     return ret;
242 }
243 
MoveProcess(int32_t dx,int32_t dy)244 void VirtualMouse::MoveProcess(int32_t dx, int32_t dy)
245 {
246     CALL_DEBUG_ENTER;
247     sptr<Rosen::Display> display = Rosen::DisplayManager::GetInstance().GetDisplayById(0);
248     CHKPV(display);
249     g_screenWidth = display->GetWidth();
250     g_screenHeight = display->GetHeight();
251     MMI::InputManager *inputMgr = MMI::InputManager::GetInstance();
252     CHKPV(inputMgr);
253     auto monitor = std::make_shared<PointerPositionMonitor>();
254     int32_t monitorId = inputMgr->AddMonitor(monitor);
255     if (monitorId < 0) {
256         FI_HILOGE("Failed to add mouse monitor");
257         return;
258     }
259     Move(MOVE_VALUE_X, MOVE_VALUE_Y);
260     Move(-MOVE_VALUE_Y, -MOVE_VALUE_X);
261     int32_t currentX = monitor->GetX();
262     int32_t currentY = monitor->GetY();
263     int32_t targetX = currentX + dx;
264     int32_t targetY = currentY + dy;
265     FI_HILOGD("Expected coordinates, (targetX, targetY):(%{private}d, %{private}d)", targetX, targetY);
266     Move(dx, dy);
267     if ((targetX <= g_screenWidth && targetX >= 0) && (targetY <= g_screenHeight && targetY >= 0) &&
268         (currentX < g_screenWidth && currentX > 0) && (currentY < g_screenHeight && currentY > 0)) {
269         int32_t nLoops = 5;
270         while (nLoops-- > 0) {
271             currentX = monitor->GetX();
272             currentY = monitor->GetY();
273             if (targetX == currentX && targetY == currentY) {
274                 break;
275             }
276             Move(targetX - currentX, targetY - currentY);
277         }
278     }
279     inputMgr->RemoveMonitor(monitorId);
280 }
281 } // namespace DeviceStatus
282 } // namespace Msdp
283 } // namespace OHOS