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