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