• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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