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_builder.h" 17 18#include <getopt.h> 19#include <fstream> 20#include <iostream> 21#include <unordered_map> 22 23#include <linux/input.h> 24 25#include "input_manager.h" 26 27#include "devicestatus_define.h" 28#include "fi_log.h" 29#include "utility.h" 30#include "virtual_mouse.h" 31 32#undef LOG_TAG 33#define LOG_TAG "VirtualMouseBuilder" 34 35namespace OHOS { 36namespace Msdp { 37namespace DeviceStatus { 38namespace { 39constexpr int32_t MAXIMUM_LEVEL_ALLOWED { 3 }; 40constexpr uint32_t IO_FLAG_WIDTH { 6 }; 41const std::unordered_map<std::string, int32_t> mouseBtns { 42 { "BTN_LEFT", BTN_LEFT }, { "BTN_RIGHT", BTN_RIGHT }, 43 { "BTN_MIDDLE", BTN_MIDDLE }, { "BTN_SIDE", BTN_SIDE }, 44 { "BTN_EXTRA", BTN_EXTRA }, { "BTN_FORWARD", BTN_FORWARD }, 45 { "BTN_BACK", BTN_BACK }, { "BTN_TASK", BTN_TASK } }; 46} // namespace 47 48VirtualMouseBuilder::VirtualMouseBuilder() : VirtualDeviceBuilder(GetDeviceName(), BUS_USB, 0x93a, 0x2510) 49{ 50 eventTypes_ = { EV_KEY, EV_REL, EV_MSC }; 51 keys_ = { BTN_LEFT, BTN_RIGHT, BTN_MIDDLE, BTN_SIDE, BTN_EXTRA, BTN_FORWARD, BTN_BACK, BTN_TASK }; 52 relBits_ = { REL_X, REL_Y, REL_WHEEL, REL_WHEEL_HI_RES }; 53 miscellaneous_ = { MSC_SCAN }; 54} 55 56class MouseEventMonitor final : public MMI::IInputEventConsumer { 57public: 58 MouseEventMonitor() = default; 59 ~MouseEventMonitor() = default; 60 61 void OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const override {}; 62 void OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const override; 63 void OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const override {}; 64}; 65 66void MouseEventMonitor::OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const 67{ 68 CHKPV(pointerEvent); 69 if (pointerEvent->GetSourceType() != MMI::PointerEvent::SOURCE_TYPE_MOUSE) { 70 return; 71 } 72 MMI::PointerEvent::PointerItem pointerItem; 73 if (!pointerEvent->GetPointerItem(pointerEvent->GetPointerId(), pointerItem)) { 74 return; 75 } 76 std::cout << "\rcurrent pointer position - x: " << std::setw(IO_FLAG_WIDTH) << std::left << 77 pointerItem.GetDisplayX() << "y: " << pointerItem.GetDisplayY() << " "; 78 std::cout.flush(); 79} 80 81std::string VirtualMouseBuilder::GetDeviceName() 82{ 83 return std::string("Virtual Mouse"); 84} 85 86void VirtualMouseBuilder::ShowUsage() 87{ 88 std::cout << "Usage: vdevadm act -t M [-d <mouse-button>] [-u <mouse-button>] [-s <dv>]" << std::endl; 89 std::cout << " [-m <dx> [<dy>]] [-M <x> <y>] [-w <ms>] [-f <FILE>] [-r <FILE>]" << std::endl; 90 std::cout << " -d <mouse-button>" << std::endl; 91 std::cout << " Down the <mouse-button>" << std::endl; 92 std::cout << " -u <mouse-button>" << std::endl; 93 std::cout << " Release the <mouse-button>" << std::endl; 94 std::cout << " -s <dy> Scroll the mouse wheel" << std::endl; 95 std::cout << " -m <dx> [<dy>]" << std::endl; 96 std::cout << " Move the mouse along <dx, dy>; if <dy> is missing, then set dy=dx" << std::endl; 97 std::cout << " -M <x> <y> Move the pointer to <x, y>" << std::endl; 98 std::cout << " -D <SLOT> <sx> <sy> <tx> <ty> Drag the touch <SLOT> to (tx, ty)" << std::endl; 99 std::cout << " -w <ms> Wait for <ms> milliseconds." << std::endl; 100 std::cout << " -f <FILE> Read actions from <FILE>" << std::endl; 101 std::cout << " -r <FILE> Read raw input data from <FILE>." << std::endl; 102 std::cout << std::endl; 103 std::cout << " <mouse-button> can be:" << std::endl; 104 std::cout << " L For left mouse button" << std::endl; 105 std::cout << " R For right mouse button" << std::endl; 106 std::cout << " M For middle mouse button" << std::endl; 107} 108 109void VirtualMouseBuilder::Mount() 110{ 111 CALL_DEBUG_ENTER; 112 std::cout << "Start to mount virtual mouse." << std::endl; 113 if (VirtualMouse::GetDevice() != nullptr) { 114 std::cout << "Virtual mouse has been mounted." << std::endl; 115 return; 116 } 117 VirtualMouseBuilder vMouse; 118 if (!vMouse.SetUp()) { 119 std::cout << "Failed to mount virtual mouse." << std::endl; 120 return; 121 } 122 123 int32_t nTries = 6; 124 do { 125 std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME)); 126 } while ((nTries-- > 0) && (VirtualMouse::GetDevice() == nullptr)); 127 if (VirtualMouse::GetDevice() == nullptr) { 128 std::cout << "Failed to mount virtual mouse." << std::endl; 129 return; 130 } 131 132 std::cout << "Mount virtual mouse successfully." << std::endl; 133 VirtualDeviceBuilder::Daemonize(); 134 135 for (;;) { 136 std::this_thread::sleep_for(std::chrono::minutes(1)); 137 } 138} 139 140void VirtualMouseBuilder::Unmount() 141{ 142 CALL_DEBUG_ENTER; 143 VirtualDeviceBuilder::Unmount("mouse", "M"); 144} 145 146void VirtualMouseBuilder::Clone() 147{ 148 CALL_DEBUG_ENTER; 149 if (VirtualMouse::GetDevice() != nullptr) { 150 std::cout << "Virtual mouse has been mounted." << std::endl; 151 return; 152 } 153 154 std::vector<std::shared_ptr<VirtualDevice>> vDevs; 155 int32_t ret = VirtualDeviceBuilder::ScanFor( 156 [](std::shared_ptr<VirtualDevice> vDev) { return ((vDev != nullptr) && vDev->IsMouse()); }, vDevs); 157 if (ret != RET_OK) { 158 std::cout << "Failed while scanning for mouse." << std::endl; 159 return; 160 } 161 auto vDev = VirtualDeviceBuilder::Select(vDevs, "mouse"); 162 CHKPV(vDev); 163 164 std::cout << "Cloning \'" << vDev->GetName() << "\'." << std::endl; 165 VirtualDeviceBuilder vBuilder(GetDeviceName(), vDev); 166 if (!vBuilder.SetUp()) { 167 std::cout << "Clone \' " << vDev->GetName() << " \' is failed." << std::endl; 168 return; 169 } 170 int32_t nTries = 3; 171 do { 172 std::this_thread::sleep_for(std::chrono::seconds(1)); 173 } while ((nTries-- > 0) && (VirtualMouse::GetDevice() == nullptr)); 174 if (VirtualMouse::GetDevice() == nullptr) { 175 std::cout << "Failed to clone \' " << vDev->GetName() << " \'." << std::endl; 176 return; 177 } 178 179 std::cout << "Clone \'" << vDev->GetName() << "\' successfully." << std::endl; 180 VirtualDeviceBuilder::Daemonize(); 181 for (;;) { 182 std::this_thread::sleep_for(std::chrono::minutes(1)); 183 } 184} 185 186void VirtualMouseBuilder::Monitor() 187{ 188 CALL_DEBUG_ENTER; 189 MMI::InputManager *inputMgr = MMI::InputManager::GetInstance(); 190 CHKPV(inputMgr); 191 auto monitor = std::make_shared<MouseEventMonitor>(); 192 int32_t monitorId = inputMgr->AddMonitor(monitor); 193 if (monitorId < 0) { 194 std::cout << "Failed to add monitor." << std::endl; 195 return; 196 } 197 for (;;) { 198 std::this_thread::sleep_for(std::chrono::minutes(1)); 199 } 200} 201 202void VirtualMouseBuilder::Act(int32_t argc, char *argv[]) 203{ 204 CALL_DEBUG_ENTER; 205 int32_t opt = getopt(argc, argv, "d:u:s:m:M:f:r:w:D:"); 206 if (opt < 0) { 207 std::cout << "Vdevadm act: required option is missing" << std::endl; 208 VirtualMouseBuilder::ShowUsage(); 209 return; 210 } 211 if (VirtualMouse::GetDevice() == nullptr) { 212 std::cout << "No virtual mouse." << std::endl; 213 return; 214 } 215 do { 216 { 217 auto action = ruleMouseActions_.find(opt); 218 if (action != ruleMouseActions_.end()) { 219 action->second(); 220 continue; 221 } 222 } 223 { 224 auto action = readMouseActions_.find(opt); 225 if (action != readMouseActions_.end()) { 226 action->second(optarg); 227 continue; 228 } 229 } 230 { 231 auto action = moveMouseActions_.find(opt); 232 if (action != moveMouseActions_.end()) { 233 action->second(argc, argv); 234 continue; 235 } 236 } 237 if (opt == 'w') { 238 VirtualDeviceBuilder::WaitFor(optarg, "mouse"); 239 } else { 240 ShowUsage(); 241 } 242 } while ((opt = getopt(argc, argv, "d:u:s:m:M:f:r:w:D:")) >= 0); 243} 244 245void VirtualMouseBuilder::ReadDownAction() 246{ 247 CALL_DEBUG_ENTER; 248 CHKPV(optarg); 249 250 if (strcmp(optarg, "L") == 0) { 251 std::cout << "[mouse] down button: BTN_LEFT" << std::endl; 252 VirtualMouse::GetDevice()->DownButton(BTN_LEFT); 253 } else if (strcmp(optarg, "M") == 0) { 254 std::cout << "[mouse] down button: BTN_MIDDLE" << std::endl; 255 VirtualMouse::GetDevice()->DownButton(BTN_MIDDLE); 256 } else if (strcmp(optarg, "R") == 0) { 257 std::cout << "[mouse] down button: BTN_RIGHT" << std::endl; 258 VirtualMouse::GetDevice()->DownButton(BTN_RIGHT); 259 } else { 260 std::cout << "Invalid argument for option \'-d\'." << std::endl; 261 ShowUsage(); 262 } 263} 264 265void VirtualMouseBuilder::ReadMoveAction(int32_t argc, char *argv[]) 266{ 267 CALL_DEBUG_ENTER; 268 CHKPV(optarg); 269 if (!Utility::IsInteger(std::string(optarg)) || (optind < 0) || (optind >= argc) || 270 !Utility::IsInteger(argv[optind])) { 271 std::cout << "Invalid arguments for Option \'-m\'." << std::endl; 272 ShowUsage(); 273 return; 274 } 275 int32_t dx = std::atoi(optarg); 276 int32_t dy = dx; 277 278 if ((argv[optind] != nullptr) && Utility::IsInteger(std::string(argv[optind]))) { 279 dy = std::atoi(argv[optind++]); 280 } 281 std::cout << "[mouse] move: (" << dx << "," << dy << ")" << std::endl; 282 VirtualMouse::GetDevice()->MoveProcess(dx, dy); 283} 284 285void VirtualMouseBuilder::ReadMoveToAction(int32_t argc, char *argv[]) 286{ 287 CALL_DEBUG_ENTER; 288 CHKPV(optarg); 289 290 if (!Utility::IsInteger(optarg) || (optind < 0) || (optind >= argc) || !Utility::IsInteger(argv[optind])) { 291 std::cout << "Invalid arguments for Option \'-M\'." << std::endl; 292 ShowUsage(); 293 return; 294 } 295 int32_t x = std::atoi(optarg); 296 int32_t y = std::atoi(argv[optind]); 297 std::cout << "[mouse] move-to (" << x << "," << y << ")" << std::endl; 298 VirtualMouse::GetDevice()->MoveTo(x, y); 299 while ((optind < argc) && Utility::IsInteger(argv[optind])) { 300 optind++; 301 } 302} 303 304void VirtualMouseBuilder::ReadDragToAction(int32_t argc, char *argv[]) 305{ 306 CALL_DEBUG_ENTER; 307 CHKPV(optarg); 308 if (!Utility::IsInteger(optarg) || (optind < 0) || (optind >= argc) || !Utility::IsInteger(argv[optind])) { 309 std::cout << "Invalid arguments for Option \'-D\'." << std::endl; 310 ShowUsage(); 311 return; 312 } 313 int32_t x = std::atoi(optarg); 314 int32_t y = std::atoi(argv[optind]); 315 316 std::cout << "[mouse] drag-to (" << x << "," << y << ")" << std::endl; 317 VirtualMouse::GetDevice()->DownButton(BTN_LEFT); 318 VirtualDeviceBuilder::WaitFor("mouse", SLEEP_TIME); 319 VirtualMouse::GetDevice()->MoveTo(x, y); 320 VirtualMouse::GetDevice()->UpButton(BTN_LEFT); 321 while ((optind < argc) && Utility::IsInteger(argv[optind])) { 322 optind++; 323 } 324} 325 326void VirtualMouseBuilder::ReadUpAction() 327{ 328 CALL_DEBUG_ENTER; 329 CHKPV(optarg); 330 331 if (strcmp(optarg, "L") == 0) { 332 std::cout << "[mouse] release button: BTN_LEFT" << std::endl; 333 VirtualMouse::GetDevice()->UpButton(BTN_LEFT); 334 } else if (strcmp(optarg, "M") == 0) { 335 std::cout << "[mouse] release button: BTN_MIDDLE" << std::endl; 336 VirtualMouse::GetDevice()->UpButton(BTN_MIDDLE); 337 } else if (strcmp(optarg, "R") == 0) { 338 std::cout << "[mouse] release button: BTN_RIGHT" << std::endl; 339 VirtualMouse::GetDevice()->UpButton(BTN_RIGHT); 340 } else { 341 std::cout << "Invalid argument for option \'-u\'." << std::endl; 342 ShowUsage(); 343 } 344} 345 346void VirtualMouseBuilder::ReadScrollAction() 347{ 348 CALL_DEBUG_ENTER; 349 CHKPV(optarg); 350 if (!Utility::IsInteger(std::string(optarg))) { 351 std::cout << "Invalid arguments for Option \'-s\'." << std::endl; 352 ShowUsage(); 353 return; 354 } 355 int32_t dy = std::atoi(optarg); 356 std::cout << "[mouse] scroll: " << dy << std::endl; 357 VirtualMouse::GetDevice()->Scroll(dy); 358} 359 360void VirtualMouseBuilder::ReadActions(const char *path) 361{ 362 CALL_DEBUG_ENTER; 363 json model; 364 int32_t result = VirtualDeviceBuilder::ReadFile(path, model); 365 if (result == RET_ERR) { 366 FI_HILOGE("Failed to read mouse data from the files"); 367 return; 368 } 369 ReadModel(model, MAXIMUM_LEVEL_ALLOWED); 370} 371 372void VirtualMouseBuilder::ReadModel(const nlohmann::json &model, int32_t level) 373{ 374 CALL_DEBUG_ENTER; 375 if (model.is_object()) { 376 auto tIter = model.find("actions"); 377 if (tIter != model.cend() && tIter->is_array()) { 378 std::for_each(tIter->cbegin(), tIter->cend(), [](const auto &item) { ReadAction(item); }); 379 } 380 } else if (model.is_array() && level > 0) { 381 for (const auto &m : model) { 382 ReadModel(m, level - 1); 383 } 384 } 385} 386 387void VirtualMouseBuilder::ReadAction(const nlohmann::json &model) 388{ 389 CALL_DEBUG_ENTER; 390 if (!model.is_object()) { 391 FI_HILOGD("Not an object"); 392 return; 393 } 394 auto it = model.find("action"); 395 if (it != model.cend() && it->is_string()) { 396 static const std::unordered_map<std::string, std::function<void(const nlohmann::json &model)>> actions { 397 { "down", &HandleDown }, 398 { "move", &HandleMove }, 399 { "up", &HandleUp }, 400 { "scroll", &HandleScroll }, 401 { "wait", &HandleWait } 402 }; 403 auto actionItr = actions.find(it.value()); 404 if (actionItr != actions.cend()) { 405 actionItr->second(model); 406 } 407 } 408} 409 410void VirtualMouseBuilder::HandleDown(const nlohmann::json &model) 411{ 412 CALL_DEBUG_ENTER; 413 auto it = model.find("button"); 414 if (it != model.cend() && it->is_string()) { 415 auto tIter = mouseBtns.find(it.value()); 416 if (tIter != mouseBtns.cend()) { 417 std::cout << "[mouse] down button: " << tIter->first << std::endl; 418 VirtualMouse::GetDevice()->DownButton(tIter->second); 419 } 420 } 421} 422 423void VirtualMouseBuilder::HandleMove(const nlohmann::json &model) 424{ 425 CALL_DEBUG_ENTER; 426 int32_t dx = 0; 427 int32_t dy = 0; 428 429 auto it = model.find("dx"); 430 if (it != model.cend() && it->is_number_integer()) { 431 dx = it.value(); 432 } 433 it = model.find("dy"); 434 if (it != model.cend() && it->is_number_integer()) { 435 dy = it.value(); 436 } 437 std::cout << "[mouse] move: (" << dx << "," << dy << ")" << std::endl; 438 VirtualMouse::GetDevice()->Move(dx, dy); 439} 440 441void VirtualMouseBuilder::HandleUp(const nlohmann::json &model) 442{ 443 CALL_DEBUG_ENTER; 444 auto it = model.find("button"); 445 if (it != model.cend() && it->is_string()) { 446 auto tIter = mouseBtns.find(it.value()); 447 if (tIter != mouseBtns.cend()) { 448 std::cout << "[mouse] release button: " << tIter->first << std::endl; 449 VirtualMouse::GetDevice()->UpButton(tIter->second); 450 } 451 } 452} 453 454void VirtualMouseBuilder::HandleScroll(const nlohmann::json &model) 455{ 456 CALL_DEBUG_ENTER; 457 auto it = model.find("dy"); 458 if (it != model.cend() && it->is_number_integer()) { 459 int32_t dy = it.value(); 460 std::cout << "[mouse] scroll: " << dy << std::endl; 461 VirtualMouse::GetDevice()->Scroll(dy); 462 } 463} 464 465void VirtualMouseBuilder::HandleWait(const nlohmann::json &model) 466{ 467 CALL_DEBUG_ENTER; 468 auto it = model.find("duration"); 469 if (it != model.cend() && it->is_number_integer()) { 470 int32_t waitTime = it.value(); 471 std::cout << "[mouse] wait for " << waitTime << " milliseconds" << std::endl; 472 VirtualDeviceBuilder::WaitFor("mouse", waitTime); 473 } 474} 475 476void VirtualMouseBuilder::ReadRawInput(const char *path) 477{ 478 CALL_DEBUG_ENTER; 479 json model; 480 int32_t result = VirtualDeviceBuilder::ReadFile(path, model); 481 if (result == RET_ERR) { 482 FI_HILOGE("Failed to read the raw mouse data"); 483 return; 484 } 485 ReadRawModel(model, MAXIMUM_LEVEL_ALLOWED); 486} 487 488void VirtualMouseBuilder::ReadRawModel(const nlohmann::json &model, int32_t level) 489{ 490 CALL_DEBUG_ENTER; 491 if (model.is_object()) { 492 auto typeIter = model.find("type"); 493 if (typeIter == model.cend() || !typeIter->is_string() || (std::string(typeIter.value()).compare("raw") != 0)) { 494 std::cout << "Expect raw input data." << std::endl; 495 return; 496 } 497 auto actionIter = model.find("actions"); 498 if (actionIter != model.cend() && actionIter->is_array()) { 499 std::for_each(actionIter->cbegin(), actionIter->cend(), [](const auto &item) { ReadRawData(item); }); 500 } 501 } else if (model.is_array() && level > 0) { 502 for (const auto &m : model) { 503 ReadRawModel(m, level - 1); 504 } 505 } 506} 507 508void VirtualMouseBuilder::ReadRawData(const nlohmann::json &model) 509{ 510 CALL_DEBUG_ENTER; 511 if (!model.is_object()) { 512 FI_HILOGD("Not an object"); 513 return; 514 } 515 auto codeIter = model.find("code"); 516 if (codeIter == model.cend() || !codeIter->is_number_integer()) { 517 return; 518 } 519 auto typeIter = model.find("type"); 520 if (typeIter == model.cend() || !typeIter->is_number_integer()) { 521 return; 522 } 523 auto valueIter = model.find("value"); 524 if (valueIter == model.cend() || !valueIter->is_number_integer()) { 525 return; 526 } 527 std::cout << "[virtual mouse] raw input: [" << typeIter.value() << ", " << codeIter.value() << ", " << 528 valueIter.value() << "]" << std::endl; 529 VirtualMouse::GetDevice()->SendEvent(typeIter.value(), codeIter.value(), valueIter.value()); 530} 531} // namespace DeviceStatus 532} // namespace Msdp 533} // namespace OHOS