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