/*
 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "virtual_device.h"

#include <getopt.h>
#include <sys/stat.h>

#include "virtual_crown.h"
#include "virtual_finger.h"
#include "virtual_fingerprint_key.h"
#include "virtual_fingerprint_mouse.h"
#include "virtual_gamepad.h"
#include "virtual_joystick.h"
#include "virtual_keyboard.h"
#include "virtual_keyboard_consumer_ctrl.h"
#include "virtual_keyboard_ext.h"
#include "virtual_keyboard_sys_ctrl.h"
#include "virtual_knob.h"
#include "virtual_knob_consumer_ctrl.h"
#include "virtual_knob_mouse.h"
#include "virtual_knob_sys_ctrl.h"
#include "virtual_mouse.h"
#include "virtual_pen.h"
#include "virtual_pen_keyboard.h"
#include "virtual_pen_mouse.h"
#include "virtual_pc_switch.h"
#include "virtual_pc_touchpad.h"
#include "virtual_remote_control.h"
#include "virtual_single_finger.h"
#include "virtual_single_touchscreen.h"
#include "virtual_stylus.h"
#include "virtual_touchpad.h"
#include "virtual_touchscreen.h"
#include "virtual_trackball.h"
#include "virtual_trackpad.h"
#include "virtual_trackpad_mouse.h"
#include "virtual_trackpad_sys_ctrl.h"
#include "virtual_uwb_remote_control.h"

namespace OHOS {
namespace MMI {
namespace {
constexpr int32_t FILE_SIZE_MAX = 0x5000;
constexpr int32_t INVALID_FILE_SIZE = -1;
constexpr int32_t FILE_POWER = 0777;
constexpr int32_t SLEEP_TIME = 1500000;
const std::string PROC_PATH = "/proc/";
const std::string VIRTUAL_DEVICE_NAME = "vuinput";
const std::string g_pid = std::to_string(getpid());

static inline bool IsNum(const std::string& str)
{
    std::istringstream sin(str);
    double num;
    return (sin >> num) && sin.eof();
}

static inline bool IsValidPath(const std::string& rootDir, const std::string& filePath)
{
    return (filePath.compare(0, rootDir.size(), rootDir) == 0);
}

static inline bool IsValidUinputPath(const std::string& filePath)
{
    return IsValidPath(PROC_PATH, filePath);
}

static inline bool IsFileExists(const std::string& fileName)
{
    return (access(fileName.c_str(), F_OK) == 0);
}

static bool CheckFileName(const std::string& fileName)
{
    std::string::size_type pos = fileName.find("_");
    if (pos == std::string::npos) {
        std::cout << "Failed to create file" << std::endl;
        return false;
    }
    if (!IsNum(fileName.substr(0, pos))) {
        std::cout << "File name check error" << std::endl;
        return false;
    }
    std::vector<std::string> validFileNames = {
        "mouse", "keyboard", "joystick", "trackball", "remotecontrol",
        "trackpad", "knob", "gamepad", "touchpad", "touchscreen",
        "pen", "pc", "all"
    };
    std::string deviceName = fileName.substr(pos + 1);
    bool result = std::any_of(validFileNames.begin(), validFileNames.end(), [deviceName](const std::string& str) {
        return str == deviceName;
        });
    if (!result) {
        std::cout << "Check device file name:" << fileName << std::endl;
    }
    return result;
}

static void RemoveDir(const std::string& filePath)
{
    if (filePath.empty()) {
        std::cout << "File path is empty" << std::endl;
        return;
    }
    DIR* dir = opendir(filePath.c_str());
    if (dir == nullptr) {
        std::cout << "Failed to open folder:" << filePath << std::endl;
        return;
    }
    dirent* ptr = nullptr;
    while ((ptr = readdir(dir)) != nullptr) {
        std::string tmpDirName(ptr->d_name);
        if ((tmpDirName == ".") || (tmpDirName == "..")) {
            continue;
        }
        if (ptr->d_type == DT_REG) {
            std::string rmFile = filePath + ptr->d_name;
            if (remove(rmFile.c_str()) != 0) {
                std::cout << "Remove file:" << rmFile << " failed" << std::endl;
            }
        } else if (ptr->d_type == DT_DIR) {
            RemoveDir((filePath + ptr->d_name + "/"));
        } else {
            std::cout << "File name:" << ptr << " type is error" << std::endl;
        }
    }
    if (closedir(dir) != 0) {
        std::cout << "Close dir:" << filePath << " failed" << std::endl;
    }
    if (std::remove(filePath.c_str()) != 0) {
        std::cout << "Remove dir:" << filePath <<" failed" << std::endl;
    }
}

static void StartCrown()
{
    static VirtualCrown virtualCrown;
    virtualCrown.SetUp();
}

static void StartFingerprint()
{
    static VirtualFingerprintKey fingerprintKey;
    fingerprintKey.SetUp();
    static VirtualFingerprintMouse fingerprintMouse;
    fingerprintMouse.SetUp();
}

static void StartGamePad()
{
    static VirtualGamePad virtualGamePad;
    virtualGamePad.SetUp();
}

static void StartJoystick()
{
    static VirtualJoystick virtualJoystick;
    virtualJoystick.SetUp();
}

static void StartKeyboard()
{
    static VirtualKeyboard virtualKey;
    virtualKey.SetUp();
    static VirtualKeyboardConsumerCtrl virtualKeyboardConsumerCtrl;
    virtualKeyboardConsumerCtrl.SetUp();
    static VirtualKeyboardExt virtualKeyext;
    virtualKeyext.SetUp();
    static VirtualKeyboardSysCtrl virtualKeyboardSysCtrl;
    virtualKeyboardSysCtrl.SetUp();
}

static void StartKnob()
{
    static VirtualKnob virtualKnob;
    virtualKnob.SetUp();
    static VirtualKnobConsumerCtrl virtualKnobConsumerCtrl;
    virtualKnobConsumerCtrl.SetUp();
    static VirtualKnobMouse virtualKnobMouse;
    virtualKnobMouse.SetUp();
    static VirtualKnobSysCtrl virtualKnobSysCtrl;
    virtualKnobSysCtrl.SetUp();
}

static void StartMouse()
{
    static VirtualMouse virtualMouse;
    virtualMouse.SetUp();
}

static void StartPc()
{
    static VirtualPcSwitch virtualPcSwitch;
    virtualPcSwitch.SetUp();
    static VirtualPcTouchpad virtualPcTouchpad;
    virtualPcTouchpad.SetUp();
}

static void StartPen()
{
    static VirtualPen virtualPen;
    virtualPen.SetUp();
    static VirtualPenKeyboard virtualPenKeyboard;
    virtualPenKeyboard.SetUp();
    static VirtualPenMouse virtualPenMouse;
    virtualPenMouse.SetUp();
}

static void StartRemoteControl()
{
    static VirtualRemoteControl virtualRemoteControl;
    virtualRemoteControl.SetUp();
}

static void StartTouchPad()
{
    static VirtualFinger virtualFinger;
    virtualFinger.SetUp();
    static VirtualSingleFinger virtualSingleFinger;
    virtualSingleFinger.SetUp();
    static VirtualStylus virtualStylus;
    virtualStylus.SetUp();
    static VirtualTouchpad virtualTouchpad;
    virtualTouchpad.SetUp();
}

static void StartTouchScreen()
{
    static VirtualSingleTouchScreen virtualSingleTouchScreen;
    virtualSingleTouchScreen.SetUp();
    static VirtualTouchScreen virtualTouchScreen;
    virtualTouchScreen.SetUp();
}

static void StartTrackball()
{
    static VirtualTrackball virtualTrackball;
    virtualTrackball.SetUp();
}

static void StartTrackpad()
{
    static VirtualTrackpad virtualTrackpad;
    virtualTrackpad.SetUp();
    static VirtualTrackpadMouse virtualMousepadMouse;
    virtualMousepadMouse.SetUp();
    static VirtualTrackpadSysCtrl virtualTrackpadSysCtrl;
    virtualTrackpadSysCtrl.SetUp();
}

static void StartUwbRemoteControl()
{
    static VirtualUwbRemoteControl virtualUwbRemoteControl;
    virtualUwbRemoteControl.SetUp();
}

using VirtualFun = void (*)();
std::map<std::string, VirtualFun> mapFun = {
    {"crown", &StartCrown},
    {"fingerprint", &StartFingerprint},
    {"gamepad", &StartGamePad},
    {"joystick", &StartJoystick},
    {"keyboard", &StartKeyboard},
    {"knob", &StartKnob},
    {"mouse", &StartMouse},
    {"pc", &StartPc},
    {"pen", &StartPen},
    {"remotecontrol", &StartRemoteControl},
    {"touchpad", &StartTouchPad},
    {"touchscreen", &StartTouchScreen},
    {"trackball", &StartTrackball},
    {"trackpad", &StartTrackpad},
    {"uwbremotecontrol", &StartUwbRemoteControl},
};

static void StartAllDevices()
{
    if (mapFun.empty()) {
        std::cout << "mapFun is empty" << std::endl;
        return;
    }
    for (const auto &item : mapFun) {
        (*item.second)();
    }
}
} // namespace

VirtualDevice::VirtualDevice(const std::string& deviceName, uint16_t busType,
    uint16_t vendorId, uint16_t productId)
    : deviceName_(deviceName),
      busTtype_(busType),
      vendorId_(vendorId),
      productId_(productId),
      version_(1) {}

VirtualDevice::~VirtualDevice()
{
    Close();
}

bool VirtualDevice::AddDevice(const std::string& startDeviceName)
{
    if (startDeviceName.empty()) {
        std::cout << "StartDeviceName is empty" << std::endl;
        return false;
    }
    if (!CreateHandle(startDeviceName)) {
        std::cout << "Failed to start device: " << startDeviceName <<std::endl;
        return false;
    }
    std::string symbolFile;
    symbolFile.append(g_folderPath).append(g_pid).append("_").append(startDeviceName);
    std::ofstream flagFile;
    flagFile.open(symbolFile.c_str());
    if (!flagFile.is_open()) {
        std::cout << "Failed to create file" <<std::endl;
        return false;
    }
    flagFile.close();
    return true;
}

std::vector<std::string> VirtualDevice::BrowseDirectory(const std::string& filePath)
{
    std::vector<std::string> fileList;
    DIR* dir = opendir(filePath.c_str());
    if (dir == nullptr) {
        std::cout << "Failed to open folder" << std::endl;
        return fileList;
    }
    dirent* ptr = nullptr;
    while ((ptr = readdir(dir)) != nullptr) {
        if (ptr->d_type == DT_REG) {
            if (ClearFileResidues(ptr->d_name)) {
                fileList.push_back(ptr->d_name);
            }
        }
    }
    if (closedir(dir) != 0) {
        std::cout << "Close dir:" << filePath << " failed" << std::endl;
    }
    return fileList;
}

bool VirtualDevice::CheckCommand(int32_t argc, char **argv)
{
    int32_t c = -1;
    if (!SelectOptions(argc, argv, c)) {
        std::cout << "Select option failed" << std::endl;
        return false;
    }
    if (!IsFileExists(g_folderPath)) {
        mkdir(g_folderPath.c_str(), FILE_POWER);
    }
    switch (c) {
        case 'L': {
            if (!ListOption(argc, argv)) {
                std::cout << "Device query failed" << std::endl;
                return false;
            }
            break;
        }
        case 'S': {
            if (!StartOption(argc, argv)) {
                std::cout << "Device start failed" << std::endl;
                return false;
            }
            break;
        }
        case 'C': {
            if (!CloseOption(argc, argv)) {
                std::cout << "Device close failed" << std::endl;
                return false;
            }
            break;
        }
        case '?': {
            if (!HelpOption(argc, argv)) {
                std::cout << "Failed to ask for help" << std::endl;
                return false;
            }
            break;
        }
        default: {
            std::cout << "The command line format is incorrect" << std::endl;
            return false;
        }
    }
    return true;
}

bool VirtualDevice::ClearFileResidues(const std::string& fileName)
{
    const std::string::size_type pos = fileName.find("_");
    const std::string processPath = "/proc/" + fileName.substr(0, pos) + "/";
    const std::string filePath = processPath + "cmdline";
    std::string temp;
    std::string processName;
    DIR *dir = nullptr;
    if (!CheckFileName(fileName)) {
        std::cout << "File name check error" << std::endl;
        goto RELEASE_RES1;
    }
    if (pos == std::string::npos) {
        std::cout << "Failed to create file" << std::endl;
        goto RELEASE_RES1;
    }
    if (!IsFileExists(processPath)) {
        std::cout <<  processPath << " folder does not exist" << std::endl;
        goto RELEASE_RES1;
    }
    dir = opendir(processPath.c_str());
    if (dir == nullptr) {
        std::cout << "Useless flag file:" << processPath << std::endl;
        goto RELEASE_RES1;
    }
    temp = ReadUinputToolFile(filePath);
    if (temp.empty()) {
        std::cout << "Temp is empty" << std::endl;
        goto RELEASE_RES2;
    }
    processName.append(temp);
    if (processName.find(VIRTUAL_DEVICE_NAME.c_str()) == std::string::npos) {
        std::cout << "Process name is wrong" << std::endl;
        goto RELEASE_RES2;
    }
    return true;
    RELEASE_RES1:
    if (remove((g_folderPath + fileName).c_str()) != 0) {
        std::cout << "Remove file failed" << std::endl;
    }
    return false;
    RELEASE_RES2:
    if (closedir(dir) != 0) {
        std::cout << "Close dir failed" << std::endl;
    }
    if (remove((g_folderPath + fileName).c_str()) != 0) {
        std::cout << "Remove file failed" << std::endl;
    }
    return false;
}

bool VirtualDevice::CloseDevice(const std::string& closeDeviceName, const std::vector<std::string>& deviceList)
{
    if (deviceList.empty()) {
        RemoveDir(g_folderPath);
        std::cout << "No start device" <<std::endl;
        return false;
    }
    if (closeDeviceName == "all") {
        for (const auto &it : deviceList) {
            kill(std::stoi(it), SIGKILL);
        }
        RemoveDir(g_folderPath);
        return true;
    }
    for (const auto &it : deviceList) {
        if (it.find(closeDeviceName) == 0) {
            kill(std::stoi(it), SIGKILL);
            remove((g_folderPath + it).c_str());
            if (BrowseDirectory(g_folderPath).empty()) {
                    RemoveDir(g_folderPath);
            }
            return true;
        }
    }
    std::cout << "Device shutdown failed! The PID format is incorrect" <<std::endl;
    return false;
}

bool VirtualDevice::CloseOption(int32_t argc, char **argv)
{
    std::vector<std::string> deviceList = BrowseDirectory(g_folderPath);
    if (argc != PARAMETERS_NUMBER) {
        std::cout << "Invalid Input Param, Please Check the validity of the para" << std::endl;
        return false;
    }
    if (!CloseDevice(argv[optind], deviceList)) {
        std::cout << "Failed to closed device" << std::endl;
        return false;
    }
    std::cout << "device closed successfully" << std::endl;
    return true;
}

bool VirtualDevice::CreateHandle(const std::string& deviceArgv)
{
    if (deviceArgv == "all") {
        StartAllDevices();
        return true;
    }
    if (mapFun.find(deviceArgv) == mapFun.end()) {
        std::cout << "Please enter the device type correctly" << std::endl;
        return false;
    }
    (*mapFun[deviceArgv])();
    return true;
}

bool VirtualDevice::CreateKey()
{
    auto fun = [&](int32_t uiSet, const std::vector<uint32_t>& list) ->bool {
        for (const auto &item : list) {
            if (ioctl(fd_, uiSet, item) < 0) {
                std::cout << __func__ << " not setting event type:" << item
                    << ", deviceName:" << deviceName_ << std::endl;
                return false;
            }
        }
        return true;
    };
    std::map<int32_t, std::vector<uint32_t>> uinputTypes;
    uinputTypes[UI_SET_EVBIT] = GetEventTypes();
    uinputTypes[UI_SET_KEYBIT] = GetKeys();
    uinputTypes[UI_SET_PROPBIT] = GetProperties();
    uinputTypes[UI_SET_ABSBIT] = GetAbs();
    uinputTypes[UI_SET_RELBIT] = GetRelBits();
    uinputTypes[UI_SET_MSCBIT] = GetMiscellaneous();
    uinputTypes[UI_SET_LEDBIT] = GetLeds();
    uinputTypes[UI_SET_SWBIT] = GetSwitches();
    uinputTypes[UI_SET_FFBIT] = GetRepeats();

    for (const auto &item : uinputTypes) {
        if (!fun(item.first, item.second)) {
            return false;
        }
    }
    return true;
}

void VirtualDevice::Close()
{
    if (fd_ >= 0) {
        ioctl(fd_, UI_DEV_DESTROY);
        close(fd_);
        fd_ = -1;
    }
}

bool VirtualDevice::DoIoctl(int32_t fd, int32_t request, const uint32_t value)
{
    int32_t rc = ioctl(fd, request, value);
    if (rc < 0) {
        std::cout << "Failed to ioctl" << std::endl;
        return false;
    }
    return true;
}

const std::vector<uint32_t>& VirtualDevice::GetAbs() const
{
    return abs_;
}

const std::vector<uint32_t>& VirtualDevice::GetEventTypes() const
{
    return eventTypes_;
}

int32_t VirtualDevice::GetFileSize(const std::string& filePath)
{
    struct stat statbuf = { 0 };
    if (stat(filePath.c_str(), &statbuf) != 0) {
        std::cout << "Get file size error" << std::endl;
        return INVALID_FILE_SIZE;
    }
    return statbuf.st_size;
}

const std::vector<uint32_t>& VirtualDevice::GetKeys() const
{
    return keys_;
}

const std::vector<uint32_t>& VirtualDevice::GetLeds() const
{
    return leds_;
}

const std::vector<uint32_t>& VirtualDevice::GetMiscellaneous() const
{
    return miscellaneous_;
}

const std::vector<uint32_t>& VirtualDevice::GetProperties() const
{
    return properties_;
}

const std::vector<uint32_t>& VirtualDevice::GetRelBits() const
{
    return relBits_;
}

const std::vector<uint32_t>& VirtualDevice::GetRepeats() const
{
    return repeats_;
}

const std::vector<uint32_t>& VirtualDevice::GetSwitches() const
{
    return switches_;
}

bool VirtualDevice::HelpOption(int32_t argc, char **argv)
{
    if (argc != PARAMETERS_QUERY_NUMBER) {
        std::cout << "Invalid Input Param, Please Check the validity of the para" << std::endl;
        return false;
    }
    ShowUsage();
    return true;
}

bool VirtualDevice::ListOption(int32_t argc, char **argv)
{
    if (argc != PARAMETERS_QUERY_NUMBER) {
        std::cout << "Invalid Input Param, Please Check the validity of the para" << std::endl;
        return false;
    }
    std::vector<std::string> deviceList = BrowseDirectory(g_folderPath);
    if (deviceList.empty()) {
        std::cout << "No device information to query" << std::endl;
        return true;
    }
    std::string::size_type pos;
    std::cout << "PID\tDEVICE" << std::endl;
    for (const auto &item : deviceList) {
        pos = item.find("_");
        if (pos != std::string::npos) {
            std::cout << item.substr(0, pos) << "\t" << item.substr(pos + 1, item.size() - pos - 1) << std::endl;
        }
    }
    return true;
}

std::string VirtualDevice::ReadFile(const std::string& filePath)
{
    FILE* fp = fopen(filePath.c_str(), "r");
    if (fp == nullptr) {
        std::cout << "Failed to open file: " << filePath << std::endl;
        return "";
    }
    std::string dataStr;
    char buf[256] = {};
    while (fgets(buf, sizeof(buf), fp) != nullptr) {
        dataStr += buf;
    }
    if (fclose(fp) != 0) {
        std::cout << "Failed to close file" << std::endl;
    }
    return dataStr;
}

std::string VirtualDevice::ReadUinputToolFile(const std::string& filePath)
{
    if (filePath.empty()) {
        std::cout << "FilePath is empty" << std::endl;
        return "";
    }
    char realPath[PATH_MAX] = {};
    if (realpath(filePath.c_str(), realPath) == nullptr) {
        std::cout << "Path is error" << std::endl;
        return "";
    }
    if (!IsValidUinputPath(realPath)) {
        std::cout << "File path is error" << std::endl;
        return "";
    }
    if (!IsFileExists(realPath)) {
        std::cout << "File not exist" << std::endl;
        return "";
    }
    int32_t fileSize = GetFileSize(realPath);
    if ((fileSize < 0) || (fileSize > FILE_SIZE_MAX)) {
        std::cout << "File size out of read range" << std::endl;
        return "";
    }
    return ReadFile(filePath);
}

bool VirtualDevice::SelectOptions(int32_t argc, char **argv, int32_t &opt)
{
    if (argc < PARAMETERS_QUERY_NUMBER) {
        std::cout << "Please enter options or parameters" << std::endl;
        return false;
    }
    struct option longOptions[] = {
        {"list", no_argument, nullptr, 'L'},
        {"start", no_argument, nullptr, 'S'},
        {"close", no_argument, nullptr, 'C'},
        {"help", no_argument, nullptr, '?'},
        {nullptr, 0, nullptr, 0}
    };
    std::string inputOptions = argv[optind];
    if (inputOptions.find('-') == inputOptions.npos) {
        for (uint32_t i = 0; i < sizeof(longOptions) / sizeof(struct option) - 1; ++i) {
            if (longOptions[i].name == inputOptions) {
                opt = longOptions[i].val;
                optind++;
                break;
            }
        }
    } else if ((inputOptions.length() != PARAMETERS_QUERY_NUMBER) &&
               (inputOptions[inputOptions.find('-') + 1] != '-')) {
        std::cout << "More than one short option is not supported" << std::endl;
        return false;
    } else {
        int32_t optionIndex = 0;
        opt = getopt_long(argc, argv, "LSC?", longOptions, &optionIndex);
    }
    if (opt == -1) {
        std::cout << "Nonstandard input parameters" << std::endl;
        return false;
    }
    return true;
}

bool VirtualDevice::SetAbsResolution()
{
    for (const auto &item : absInit_) {
        ioctl(fd_, UI_ABS_SETUP, &item);
    }
    return true;
}

void VirtualDevice::SetAbsValue(const AbsInfo& absInfo)
{
    uinputDev_.absmin[absInfo.code] = absInfo.minValue;
    uinputDev_.absmax[absInfo.code] = absInfo.maxValue;
    uinputDev_.absfuzz[absInfo.code] = absInfo.fuzz;
    uinputDev_.absflat[absInfo.code] = absInfo.flat;
}

void VirtualDevice::SetDeviceId()
{
    uinputDev_.id.bustype = busTtype_;
    uinputDev_.id.vendor = vendorId_;
    uinputDev_.id.product = productId_;
    uinputDev_.id.version = version_;
}

bool VirtualDevice::SetPhys(const std::string& deviceName)
{
    std::string phys;
    std::map<std::string, std::string> typeDevice = {
        {"V-Pencil",                     "pen"},
        {"V-Pencil-keyboard",            "pen"},
        {"V-Pencil-mouse",               "pen"},
        {"Virtual Finger",               "touchpad"},
        {"Virtual GamePad",              "gamepad"},
        {"Virtual Joystick",             "joystick"},
        {"Virtual KeyboardConsumerCtrl", "keyboard"},
        {"Virtual KeyboardSysCtrl",      "keyboard"},
        {"Virtual Knob",                 "knob"},
        {"Virtual KnobConsumerCtrl",     "knob"},
        {"Virtual KnobMouse",            "knob"},
        {"Virtual KnobSysCtrl",          "knob"},
        {"Virtual Mouse",                "mouse"},
        {"Virtual PcSwitch",             "pc"},
        {"Virtual PcTouchPad",           "pc"},
        {"Virtual RemoteControl",        "remotecontrol"},
        {"Virtual SingleFinger",         "touchpad"},
        {"Virtual SingleTouchScreen",    "touchscreen"},
        {"Virtual Stylus",               "touchpad"},
        {"Virtual TouchScreen",          "touchscreen"},
        {"Virtual Touchpad",             "touchpad"},
        {"Virtual TrackPadMouse",        "trackpad"},
        {"Virtual Trackball",            "trackball"},
        {"Virtual Trackpad",             "trackpad"},
        {"Virtual TrackpadSysCtrl",      "trackpad"},
        {"Virtual UWB RemoteControl",    "uwbremotecontrol"},
        {"Virtual Crown",                "mouse"},
        {"Virtual keyboard",             "keyboard"},
        {"Virtual keyboardExt",          "keyboard"},
    };
    std::string deviceType = typeDevice.find(deviceName)->second;
    phys.append(deviceType).append(g_pid).append("/").append(g_pid);

    if (ioctl(fd_, UI_SET_PHYS, phys.c_str()) < 0) {
        std::cout << "Failed to set uinput phys" << std::endl;
        return false;
    }
    return true;
}

void VirtualDevice::SetResolution(const ResolutionInfo& resolutionInfo)
{
    uinputAbs_.code = resolutionInfo.axisCode;
    uinputAbs_.absinfo.resolution = resolutionInfo.absResolution;
    absInit_.push_back(uinputAbs_);
}

bool VirtualDevice::SetUp()
{
    fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
    if (fd_ < 0) {
        std::cout << "Failed to open uinput: " << fd_ << std::endl;
        return false;
    }

    if (strncpy_s(uinputDev_.name, sizeof(uinputDev_.name), deviceName_.c_str(), deviceName_.size()) != 0) {
        std::cout << "Failed to copied device name: " << uinputDev_.name << std::endl;
        return false;
    };
    SetDeviceId();
    if (!SetAbsResolution()) {
        std::cout << "Failed to set uinput abs resolution" << std::endl;
        return false;
    }
    if (!SetPhys(deviceName_)) {
        std::cout << "Failed to set uinput phys" << std::endl;
        return false;
    }
    if (!CreateKey()) {
        std::cout << "Failed to create uinput KeyValue" << std::endl;
        return false;
    }
    if (write(fd_, &uinputDev_, sizeof(uinputDev_)) < 0) {
        std::cout << "Unable to write device info to target" << std::endl;
        return false;
    }
    if (ioctl(fd_, UI_DEV_CREATE) < 0) {
        std::cout << "Try to create uinput device filed in fd: " << fd_ << std::endl;
        return false;
    }
    return true;
}

void VirtualDevice::ShowUsage()
{
    std::cout << "Usage: vuinput <option> <command> <arg>..."      << std::endl;
    std::cout << "The option are:                                " << std::endl;
    std::cout << "commands for list:                             " << std::endl;
    std::cout << "-L      --list        list    -display virtual devices and pid information" << std::endl;
    std::cout << "commands for start:                            " << std::endl;
    std::cout << "-S <device> &   --start <device> &    start <device> &     -start a device" << std::endl;
    std::cout << " -start supported <device>-" << std::endl;
    std::cout << "  mouse"         << std::endl;
    std::cout << "  keyboard"      << std::endl;
    std::cout << "  joystick"      << std::endl;
    std::cout << "  trackball"     << std::endl;
    std::cout << "  remotecontrol" << std::endl;
    std::cout << "  trackpad"      << std::endl;
    std::cout << "  knob"          << std::endl;
    std::cout << "  gamepad"       << std::endl;
    std::cout << "  touchpad"      << std::endl;
    std::cout << "  touchscreen"   << std::endl;
    std::cout << "  pen"           << std::endl;
    std::cout << "-S all &        --start all &        start all &           -start devices " << std::endl;
    std::cout << "commands for close:                                                       " << std::endl;
    std::cout << "-C <pid>        --close <pid>        close <pid>           -close a pid   " << std::endl;
    std::cout << "-C all          --close all          close all             -close pids    " << std::endl;
    std::cout << "-?  --help   help                                                         " << std::endl;
}

bool VirtualDevice::StartOption(int32_t argc, char **argv)
{
    if (argc != PARAMETERS_NUMBER) {
        std::cout << "Invalid Input Param, Please Check the validity of the para" << std::endl;
        return false;
    }
    if (!AddDevice(argv[optind])) {
        std::cout << "Failed to create device" << std::endl;
        return false;
    }
    while (true) {
        usleep(SLEEP_TIME);
    }
    return true;
}
} // namespace MMI
} // namespace OHOS