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