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 
35 namespace OHOS {
36 namespace Msdp {
37 namespace DeviceStatus {
38 namespace {
39 constexpr int32_t MAXIMUM_LEVEL_ALLOWED { 3 };
40 constexpr uint32_t IO_FLAG_WIDTH { 6 };
41 const 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 
VirtualMouseBuilder()48 VirtualMouseBuilder::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 
56 class MouseEventMonitor final : public MMI::IInputEventConsumer {
57 public:
58     MouseEventMonitor() = default;
59     ~MouseEventMonitor() = default;
60 
OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const61     void OnInputEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) const override {};
62     void OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const override;
OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const63     void OnInputEvent(std::shared_ptr<MMI::AxisEvent> axisEvent) const override {};
64 };
65 
OnInputEvent(std::shared_ptr<MMI::PointerEvent> pointerEvent) const66 void 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 
GetDeviceName()81 std::string VirtualMouseBuilder::GetDeviceName()
82 {
83     return std::string("Virtual Mouse");
84 }
85 
ShowUsage()86 void 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 
Mount()109 void 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 
Unmount()140 void VirtualMouseBuilder::Unmount()
141 {
142     CALL_DEBUG_ENTER;
143     VirtualDeviceBuilder::Unmount("mouse", "M");
144 }
145 
Clone()146 void 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 
Monitor()186 void 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 
Act(int32_t argc,char * argv[])202 void 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 
ReadDownAction()245 void 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 
ReadMoveAction(int32_t argc,char * argv[])265 void 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 
ReadMoveToAction(int32_t argc,char * argv[])285 void 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 
ReadDragToAction(int32_t argc,char * argv[])304 void 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 
ReadUpAction()326 void 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 
ReadScrollAction()346 void 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 
ReadActions(const char * path)360 void 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 
ReadModel(const nlohmann::json & model,int32_t level)372 void 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 
ReadAction(const nlohmann::json & model)387 void 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 
HandleDown(const nlohmann::json & model)410 void 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 
HandleMove(const nlohmann::json & model)423 void 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 
HandleUp(const nlohmann::json & model)441 void 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 
HandleScroll(const nlohmann::json & model)454 void 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 
HandleWait(const nlohmann::json & model)465 void 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 
ReadRawInput(const char * path)476 void 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 
ReadRawModel(const nlohmann::json & model,int32_t level)488 void 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 
ReadRawData(const nlohmann::json & model)508 void 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