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_keyboard_builder.h"
17 
18 #include <getopt.h>
19 #include <fstream>
20 #include <iostream>
21 
22 #include "devicestatus_define.h"
23 #include "fi_log.h"
24 #include "utility.h"
25 #include "virtual_keyboard.h"
26 
27 #undef LOG_TAG
28 #define LOG_TAG "VirtualKeyboardBuilder"
29 
30 namespace OHOS {
31 namespace Msdp {
32 namespace DeviceStatus {
33 namespace {
34 constexpr int32_t MAXIMUM_LEVEL_ALLOWED { 3 };
35 constexpr ssize_t MAXIMUM_FILESIZE_ALLOWED { 0x100000 };
36 } // namespace
37 
VirtualKeyboardBuilder()38 VirtualKeyboardBuilder::VirtualKeyboardBuilder() : VirtualDeviceBuilder(GetDeviceName(), BUS_USB, 0x24ae, 0x4035)
39 {
40     eventTypes_ = { EV_KEY, EV_MSC, EV_LED, EV_REP };
41     miscellaneous_ = { MSC_SCAN };
42     leds_ = { LED_NUML, LED_CAPSL, LED_SCROLLL, LED_COMPOSE, LED_KANA };
43     repeats_ = { REP_DELAY, REP_PERIOD };
44     keys_ = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
45         21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
46         41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
47         61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80,
48         81, 82, 83, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 102,
49         103, 104, 105, 106, 107, 108, 109, 110, 111, 113, 114, 115, 116, 117, 119, 121, 122, 123, 124, 125,
50         126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 140, 142, 150, 152, 158, 159, 161,
51         163, 164, 165, 166, 173, 176, 177, 178, 179, 180, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192,
52         193, 194, 240, 211, 213, 214, 215, 218, 220, 221, 222, 223, 226, 227, 231, 232, 233, 236, 237, 238,
53         239, 242, 243, 245, 246, 247, 248, 464, 522, 523, 141, 145, 146, 147, 148, 149, 151, 153, 154, 157,
54         160, 162, 170, 175, 182, 200, 201, 202, 203, 204, 205, 101, 112, 118, 120 };
55 }
56 
GetDeviceName()57 std::string VirtualKeyboardBuilder::GetDeviceName()
58 {
59     return std::string("Virtual Keyboard");
60 }
61 
ShowUsage()62 void VirtualKeyboardBuilder::ShowUsage()
63 {
64     std::cout << "Usage: vdevadm act -t K [-d <key>] [-u <key>] [-w <ms>] [-f <FILE>] [-r <FILE>]" << std::endl;
65     std::cout << "      -d <key>    Down <key>" << std::endl;
66     std::cout << "      -u <key>    Release <key>" << std::endl;
67     std::cout << "      -w <ms>     Wait for <ms> milliseconds." << std::endl;
68     std::cout << "      -f <FILE>   Read actions from <FILE>" << std::endl;
69     std::cout << "      -r <FILE>   Read raw input data from <FILE>." << std::endl;
70     std::cout << std::endl;
71 }
72 
Mount()73 void VirtualKeyboardBuilder::Mount()
74 {
75     CALL_DEBUG_ENTER;
76     std::cout << "Start to mount virtual keyboard." << std::endl;
77     if (VirtualKeyboard::GetDevice() != nullptr) {
78         std::cout << "Virtual keyboard has been mounted." << std::endl;
79         return;
80     }
81     VirtualKeyboardBuilder vKeyboard;
82     if (!vKeyboard.SetUp()) {
83         std::cout << "Failed to mount virtual keyboard." << std::endl;
84         return;
85     }
86 
87     int32_t nTries = 6;
88     do {
89         std::this_thread::sleep_for(std::chrono::milliseconds(SLEEP_TIME));
90     } while ((nTries-- > 0) && (VirtualKeyboard::GetDevice() == nullptr));
91     if (VirtualKeyboard::GetDevice() == nullptr) {
92         std::cout << "Failed to mount virtual keyboard." << std::endl;
93         return;
94     }
95 
96     std::cout << "Mount virtual keyboard successfully." << std::endl;
97     VirtualDeviceBuilder::Daemonize();
98 
99     for (;;) {
100         std::this_thread::sleep_for(std::chrono::minutes(1));
101     }
102 }
103 
Unmount()104 void VirtualKeyboardBuilder::Unmount()
105 {
106     CALL_DEBUG_ENTER;
107     VirtualDeviceBuilder::Unmount("keyboard", "K");
108 }
109 
Clone()110 void VirtualKeyboardBuilder::Clone()
111 {
112     CALL_DEBUG_ENTER;
113     if (VirtualKeyboard::GetDevice() != nullptr) {
114         std::cout << "Virtual keyboard has been mounted" << std::endl;
115         return;
116     }
117 
118     std::vector<std::shared_ptr<VirtualDevice>> vDevs;
119     int32_t ret = VirtualDeviceBuilder::ScanFor(
120         [](std::shared_ptr<VirtualDevice> vDev) { return ((vDev != nullptr) && vDev->IsKeyboard()); }, vDevs);
121     if (ret != RET_OK) {
122         std::cout << "Failed while scanning for keyboard" << std::endl;
123         return;
124     }
125     auto vDev = VirtualDeviceBuilder::Select(vDevs, "keyboard");
126     CHKPV(vDev);
127     std::cout << "Cloning \'" << vDev->GetName() << "\'." << std::endl;
128     VirtualDeviceBuilder vBuilder(GetDeviceName(), vDev);
129     if (!vBuilder.SetUp()) {
130         std::cout << "Failed to clone \' " << vDev->GetName() << " \'." << std::endl;
131         return;
132     }
133 
134     int32_t nTries = 3;
135     do {
136         std::this_thread::sleep_for(std::chrono::seconds(1));
137     } while ((nTries-- > 0) && (VirtualKeyboard::GetDevice() == nullptr));
138     if (VirtualKeyboard::GetDevice() == nullptr) {
139         std::cout << "Failed to clone \' " << vDev->GetName() << " \'." << std::endl;
140         return;
141     }
142 
143     std::cout << "Clone \'" << vDev->GetName() << "\' successfully" << std::endl;
144     VirtualDeviceBuilder::Daemonize();
145     for (;;) {
146         std::this_thread::sleep_for(std::chrono::minutes(1));
147     }
148 }
149 
Act(int32_t argc,char * argv[])150 void VirtualKeyboardBuilder::Act(int32_t argc, char *argv[])
151 {
152     CALL_DEBUG_ENTER;
153     int32_t opt = getopt(argc, argv, "d:u:f:r:w:");
154     if (opt < 0) {
155         std::cout << "Vdevadm act: required option is missing" << std::endl;
156         ShowUsage();
157         return;
158     }
159     if (VirtualKeyboard::GetDevice() == nullptr) {
160         std::cout << "No virtual keyboard." << std::endl;
161         return;
162     }
163     do {
164         switch (opt) {
165             case 'd': {
166                 ReadDownAction();
167                 break;
168             }
169             case 'u': {
170                 ReadUpAction();
171                 break;
172             }
173             case 'f': {
174                 ReadActions(optarg);
175                 break;
176             }
177             case 'r': {
178                 ReadRawInput(optarg);
179                 break;
180             }
181             case 'w': {
182                 VirtualDeviceBuilder::WaitFor(optarg, "keyboard");
183                 break;
184             }
185             default: {
186                 ShowUsage();
187                 break;
188             }
189         }
190     } while ((opt = getopt(argc, argv, "d:u:f:r:w:")) >= 0);
191 }
192 
ReadDownAction()193 void VirtualKeyboardBuilder::ReadDownAction()
194 {
195     CALL_DEBUG_ENTER;
196     CHKPV(optarg);
197     if (!Utility::IsInteger(optarg)) {
198         std::cout << "Require arguments for Option \'-d\'." << std::endl;
199         ShowUsage();
200         return;
201     }
202 
203     int32_t key = std::atoi(optarg);
204     std::cout << "[keyboard] down key: [" << key << "]" << std::endl;
205     VirtualKeyboard::GetDevice()->Down(key);
206 }
207 
ReadUpAction()208 void VirtualKeyboardBuilder::ReadUpAction()
209 {
210     CALL_DEBUG_ENTER;
211     CHKPV(optarg);
212     if (!Utility::IsInteger(optarg)) {
213         std::cout << "Require arguments for Option \'-u\'." << std::endl;
214         ShowUsage();
215         return;
216     }
217 
218     int32_t key = std::atoi(optarg);
219     std::cout << "[keyboard] release key: [" << key << "]" << std::endl;
220     VirtualKeyboard::GetDevice()->Up(key);
221 }
222 
ReadActions(const char * path)223 void VirtualKeyboardBuilder::ReadActions(const char *path)
224 {
225     CALL_DEBUG_ENTER;
226     CHKPV(path);
227     char realPath[PATH_MAX] {};
228     if (realpath(path, realPath) == nullptr) {
229         std::cout << "[keyboard] an invalid path: " << path << std::endl;
230         return;
231     }
232     if (Utility::GetFileSize(realPath) > MAXIMUM_FILESIZE_ALLOWED) {
233         std::cout << "[keyboard] the file size is too large" << std::endl;
234         return;
235     }
236     json model;
237     int32_t ret = VirtualDeviceBuilder::ReadFile(realPath, model);
238     if (ret == RET_ERR) {
239         FI_HILOGE("Failed to read the file");
240         return;
241     }
242     ReadModel(model, MAXIMUM_LEVEL_ALLOWED);
243 }
244 
ReadModel(const nlohmann::json & model,int32_t level)245 void VirtualKeyboardBuilder::ReadModel(const nlohmann::json &model, int32_t level)
246 {
247     CALL_DEBUG_ENTER;
248     if (!model.is_object() && !model.is_array()) {
249         FI_HILOGE("model is not an array or object");
250         return;
251     }
252     if (model.is_object()) {
253         auto tIter = model.find("actions");
254         if (tIter != model.cend() && tIter->is_array()) {
255             std::for_each(tIter->cbegin(), tIter->cend(), [](const auto &item) { ReadAction(item); });
256         }
257     }
258     if (model.is_array() && level > 0) {
259         for (const auto &m : model) {
260             ReadModel(m, level - 1);
261         }
262     }
263 }
264 
ReadAction(const nlohmann::json & model)265 void VirtualKeyboardBuilder::ReadAction(const nlohmann::json &model)
266 {
267     CALL_DEBUG_ENTER;
268     if (!model.is_object()) {
269         FI_HILOGD("Not an object");
270         return;
271     }
272     auto it = model.find("action");
273     if (it != model.cend() && it->is_string()) {
274         static const std::unordered_map<std::string, std::function<void(const nlohmann::json &model)>> actions {
275             { "down", &VirtualKeyboardBuilder::HandleDown },
276             { "up", &VirtualKeyboardBuilder::HandleUp },
277             { "wait", &VirtualKeyboardBuilder::HandleWait }
278         };
279         auto actionItr = actions.find(it.value());
280         if (actionItr != actions.cend()) {
281             actionItr->second(model);
282         }
283     }
284 }
285 
HandleDown(const nlohmann::json & model)286 void VirtualKeyboardBuilder::HandleDown(const nlohmann::json &model)
287 {
288     CALL_DEBUG_ENTER;
289     auto it = model.find("key");
290     if (it != model.cend() && it->is_number_integer()) {
291         std::cout << "[virtual keyboard] down key: " << it.value() << std::endl;
292         VirtualKeyboard::GetDevice()->Down(it.value());
293     }
294 }
295 
HandleUp(const nlohmann::json & model)296 void VirtualKeyboardBuilder::HandleUp(const nlohmann::json &model)
297 {
298     CALL_DEBUG_ENTER;
299     auto it = model.find("key");
300     if (it != model.cend() && it->is_number_integer()) {
301         std::cout << "[virtual keyboard] release key: " << it.value() << std::endl;
302         VirtualKeyboard::GetDevice()->Up(it.value());
303     }
304 }
305 
HandleWait(const nlohmann::json & model)306 void VirtualKeyboardBuilder::HandleWait(const nlohmann::json &model)
307 {
308     CALL_DEBUG_ENTER;
309     auto it = model.find("duration");
310     if (it != model.cend() && it->is_number_integer()) {
311         int32_t waitTime = it.value();
312         std::cout << "[virtual keyboard] wait for " << waitTime << " milliseconds" << std::endl;
313         VirtualDeviceBuilder::WaitFor("virtual keyboard", waitTime);
314     }
315 }
316 
ReadRawInput(const char * path)317 void VirtualKeyboardBuilder::ReadRawInput(const char *path)
318 {
319     CALL_DEBUG_ENTER;
320     CHKPV(path);
321     char realPath[PATH_MAX] {};
322 
323     if (realpath(path, realPath) == nullptr) {
324         std::cout << "[keyboard] invalid path: " << path << std::endl;
325         return;
326     }
327     if (Utility::GetFileSize(realPath) > MAXIMUM_FILESIZE_ALLOWED) {
328         std::cout << "[keyboard] file is too large" << std::endl;
329         return;
330     }
331     json model;
332 
333     int32_t ret = VirtualDeviceBuilder::ReadFile(realPath, model);
334     if (ret == RET_ERR) {
335         FI_HILOGE("Failed to read raw input data");
336         return;
337     }
338     ReadRawModel(model, MAXIMUM_LEVEL_ALLOWED);
339 }
340 
ReadRawModel(const nlohmann::json & model,int32_t level)341 void VirtualKeyboardBuilder::ReadRawModel(const nlohmann::json &model, int32_t level)
342 {
343     CALL_DEBUG_ENTER;
344     if (!model.is_object() && !model.is_array()) {
345         FI_HILOGE("model is not an array or object");
346         return;
347     }
348     if (model.is_object()) {
349         auto typeIter = model.find("type");
350         if (typeIter == model.cend() || !typeIter->is_string() || (std::string(typeIter.value()).compare("raw") != 0)) {
351             std::cout << "Expect raw input data" << std::endl;
352             return;
353         }
354         auto actionIter = model.find("actions");
355         if (actionIter != model.cend() && actionIter->is_array()) {
356             std::for_each(actionIter->cbegin(), actionIter->cend(), [](const auto &item) { ReadRawData(item); });
357         }
358     }
359     if (model.is_array() && level > 0) {
360         for (const auto &m : model) {
361             ReadRawModel(m, level - 1);
362         }
363     }
364 }
365 
ReadRawData(const nlohmann::json & model)366 void VirtualKeyboardBuilder::ReadRawData(const nlohmann::json &model)
367 {
368     CALL_DEBUG_ENTER;
369     if (!model.is_object()) {
370         FI_HILOGE("model is not an object");
371         return;
372     }
373     auto valueIter = model.find("value");
374     if (valueIter == model.cend() || !valueIter->is_number_integer()) {
375         return;
376     }
377     auto codeIter = model.find("code");
378     if (codeIter == model.cend() || !codeIter->is_number_integer()) {
379         return;
380     }
381     auto typeIter = model.find("type");
382     if (typeIter == model.cend() || !typeIter->is_number_integer()) {
383         return;
384     }
385     std::cout << "[virtual keyboard] raw input: [" << typeIter.value() << ", " << codeIter.value() << ", " <<
386         valueIter.value() << "]" << std::endl;
387     VirtualKeyboard::GetDevice()->SendEvent(typeIter.value(), codeIter.value(), valueIter.value());
388 }
389 } // namespace DeviceStatus
390 } // namespace Msdp
391 } // namespace OHOS