• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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