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 30namespace OHOS { 31namespace Msdp { 32namespace DeviceStatus { 33namespace { 34constexpr int32_t MAXIMUM_LEVEL_ALLOWED { 3 }; 35constexpr ssize_t MAXIMUM_FILESIZE_ALLOWED { 0x100000 }; 36} // namespace 37 38VirtualKeyboardBuilder::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 57std::string VirtualKeyboardBuilder::GetDeviceName() 58{ 59 return std::string("Virtual Keyboard"); 60} 61 62void 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 73void 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 104void VirtualKeyboardBuilder::Unmount() 105{ 106 CALL_DEBUG_ENTER; 107 VirtualDeviceBuilder::Unmount("keyboard", "K"); 108} 109 110void 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 150void 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 193void 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 208void 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 223void 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 245void 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 265void 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 286void 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 296void 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 306void 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 317void 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 341void 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 366void 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