* Copyright (c) 2021-2022 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 <fcntl.h>
#include <securec.h>
#include <unistd.h>
#include "mmi_log.h"
#undef MMI_LOG_TAG
#define MMI_LOG_TAG "VirtualDevice"
namespace OHOS {
namespace MMI {
namespace {
using namespace OHOS::HiviewDFX;
constexpr uint32_t MAX_NAME_LENGTH { 80 };
bool DoIoctl(int32_t fd, int32_t request, const uint32_t value)
{
int32_t rc = ioctl(fd, request, value);
if (rc < 0) {
MMI_HILOGE("Failed to ioctl");
return false;
}
return true;
}
}
VirtualDevice::VirtualDevice(const char *deviceName, uint16_t productId)
: deviceName_(deviceName),
busType_(BUS_USB),
vendorId_(0x6006),
productId_(productId),
version_(1) {}
VirtualDevice::~VirtualDevice()
{
if (fd_ >= 0) {
ioctl(fd_, UI_DEV_DESTROY);
close(fd_);
fd_ = -1;
}
}
bool VirtualDevice::SetUp()
{
fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (fd_ < 0) {
MMI_HILOGE("Failed to open uinput");
return false;
}
for (const auto &item : GetEventTypes()) {
if (!DoIoctl(fd_, UI_SET_EVBIT, item)) {
MMI_HILOGE("Error setting event type:%{public}u", item);
return false;
}
}
for (const auto &item : GetKeys()) {
if (!DoIoctl(fd_, UI_SET_KEYBIT, item)) {
MMI_HILOGE("Error setting key:%{public}u", item);
return false;
}
}
for (const auto &item : GetProperties()) {
if (!DoIoctl(fd_, UI_SET_PROPBIT, item)) {
MMI_HILOGE("Error setting property:%{public}u", item);
return false;
}
}
for (const auto &item : GetAbs()) {
if (!DoIoctl(fd_, UI_SET_ABSBIT, item)) {
MMI_HILOGE("Error setting property:%{public}u", item);
return false;
}
}
for (const auto &item : GetRelBits()) {
if (!DoIoctl(fd_, UI_SET_RELBIT, item)) {
MMI_HILOGE("Error setting rel:%{public}u", item);
return false;
}
}
return SetUpExt();
}
bool VirtualDevice::SetUpExt()
{
errno_t ret = strncpy_s(dev_.name, MAX_NAME_LENGTH, deviceName_, sizeof(dev_.name));
if (ret != EOK) {
MMI_HILOGE("Failed to copy deviceName");
return false;
}
dev_.id.bustype = busType_;
dev_.id.vendor = vendorId_;
dev_.id.product = productId_;
dev_.id.version = version_;
if (write(fd_, &dev_, sizeof(dev_)) < 0) {
MMI_HILOGE("Unable to set input device info");
return false;
}
if (ioctl(fd_, UI_DEV_CREATE) < 0) {
MMI_HILOGE("Unable to create input device");
return false;
}
return true;
}
bool VirtualDevice::EmitEvent(uint16_t type, uint16_t code, uint32_t value) const
{
struct input_event event {};
event.type = type;
event.code = code;
event.value = value;
#ifndef __MUSL__
gettimeofday(&event.time, nullptr);
#endif
if (write(fd_, &event, sizeof(event)) < static_cast<ssize_t>(sizeof(event))) {
MMI_HILOGE("Event write failed");
return false;
}
return true;
}
const std::vector<uint32_t> &VirtualDevice::GetEventTypes() const
{
static const std::vector<uint32_t> evtTypes {};
return evtTypes;
}
const std::vector<uint32_t> &VirtualDevice::GetKeys() const
{
static const std::vector<uint32_t> keys {};
return keys;
}
const std::vector<uint32_t> &VirtualDevice::GetProperties() const
{
static const std::vector<uint32_t> properties {};
return properties;
}
const std::vector<uint32_t> &VirtualDevice::GetAbs() const
{
static const std::vector<uint32_t> abs {};
return abs;
}
const std::vector<uint32_t> &VirtualDevice::GetRelBits() const
{
static const std::vector<uint32_t> relBits {};
return relBits;
}
}
}