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