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