1/*
2 * Copyright (c) 2024 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 "libinput_wrapper.h"
17
18#include <cinttypes>
19#include <climits>
20#include <iostream>
21
22#include <dirent.h>
23#include <fcntl.h>
24#include <sys/epoll.h>
25#include <unistd.h>
26
27#include "define_multimodal.h"
28#include "util.h"
29
30#undef MMI_LOG_DOMAIN
31#define MMI_LOG_DOMAIN MMI_LOG_SERVER
32#undef MMI_LOG_TAG
33#define MMI_LOG_TAG "LibinputWrapper"
34
35namespace OHOS {
36namespace MMI {
37namespace {
38constexpr int32_t WAIT_TIME_FOR_INPUT { 10 };
39constexpr int32_t MAX_RETRY_COUNT { 5 };
40} // namespace
41
42LibinputWrapper::~LibinputWrapper()
43{
44    if (input_ != nullptr) {
45        libinput_unref(input_);
46    }
47}
48
49constexpr static libinput_interface LIBINPUT_INTERFACE = {
50    .open_restricted = [](const char *path, int32_t flags, void *user_data)->int32_t {
51        if (path == nullptr) {
52            MMI_HILOGWK("Input device path is nullptr");
53            return RET_ERR;
54        }
55        char realPath[PATH_MAX] = {};
56        if (realpath(path, realPath) == nullptr) {
57            std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_INPUT));
58            MMI_HILOGWK("The error path is %{private}s", path);
59            return RET_ERR;
60        }
61        int32_t fd;
62        for (int32_t i = 0; i < MAX_RETRY_COUNT; i++) {
63            fd = open(realPath, flags);
64            if (fd >= 0) {
65                break;
66            }
67            std::this_thread::sleep_for(std::chrono::milliseconds(WAIT_TIME_FOR_INPUT));
68        }
69        int32_t errNo = errno;
70        MMI_HILOGWK("Libinput .open_restricted path:%{private}s,fd:%{public}d,errno:%{public}d", path, fd, errNo);
71        return fd < 0 ? RET_ERR : fd;
72    },
73    .close_restricted = [](int32_t fd, void *user_data)
74    {
75        if (fd < 0) {
76            return;
77        }
78        MMI_HILOGI("Libinput .close_restricted fd:%{public}d", fd);
79        close(fd);
80    },
81};
82
83bool LibinputWrapper::Init()
84{
85    input_ = libinput_path_create_context(&LIBINPUT_INTERFACE, nullptr);
86    CHKPF(input_);
87    fd_ = libinput_get_fd(input_);
88    if (fd_ < 0) {
89        libinput_unref(input_);
90        fd_ = -1;
91        return false;
92    }
93    return true;
94}
95
96struct libinput_event* LibinputWrapper::Dispatch()
97{
98    CHKPP(input_);
99    if (libinput_dispatch(input_) != 0) {
100        std::cout << "Failed to dispatch input event" << std::endl;
101        return nullptr;
102    }
103    return libinput_get_event(input_);
104}
105
106void LibinputWrapper::DrainEvents()
107{
108    CHKPV(input_);
109    struct libinput_event *event;
110
111    libinput_dispatch(input_);
112    while ((event = libinput_get_event(input_))) {
113        libinput_event_destroy(event);
114        libinput_dispatch(input_);
115    }
116}
117
118bool LibinputWrapper::AddPath(const std::string &path)
119{
120    CHKPF(input_);
121    auto pos = devices_.find(path);
122    if (pos != devices_.end()) {
123        return true;
124    }
125    libinput_device* device = libinput_path_add_device(input_, path.c_str());
126    CHKPF(device);
127    devices_[std::move(path)] = libinput_device_ref(device);
128    return true;
129}
130
131void LibinputWrapper::RemovePath(const std::string &path)
132{
133    CHKPV(input_);
134    auto pos = devices_.find(path);
135    if (pos != devices_.end()) {
136        libinput_path_remove_device(pos->second);
137        libinput_device_unref(pos->second);
138        devices_.erase(pos);
139    }
140}
141} // namespace MMI
142} // namespace OHOS
143