在不适配HDF(Hardware Driver Foundation)的情况下,OH(OpenHarmony)中Updater 触摸功能当前无法正常使用。为此,我们提出一种实现触摸功能的支持方案。

主要思路如下:

通过使用 epoll 监听 Linux Input 子系统上报的事件信息,对事件进行解析和处理后,将相关触摸数据送入 PointersInputDevice 类的回调函数中,从而实现对 Updater 的触摸支持功能。

1. base/update/updater/services/ui/driver/input_event.cpp
创建新线程通过epoll_wait 监控设备

constexpr auto INPUT_DEVICES_PATH { "/dev/input/" };
constexpr const int MAX_EPOLL_DEVICES = 100;
constexpr const int EPOLL_TIMEOUT = -1;


InputEvent::~InputEvent() {
    if (thread_.joinable()) {
        thread_.join();
    }
    for (int fd : inputFds_) {
        close(fd);
    }
    if (epollFd_ != -1) {
        close(epollFd_);
    }
}

void InputEvent::OnThread(){
    while(true){
        epoll_event events[100]={};
        int count = epoll_wait(epollFd_, &events[0], MAX_EPOLL_DEVICES, EPOLL_TIMEOUT);
        if (count == -1) {
            LOG(INFO) << "count err";
                continue;
            }
        for (int32_t i = 0; i < count ; i++){
            struct input_event ev;
            // 从输入设备文件描述符中读取 input_event 数据
            ssize_t bytesRead = read(events[i].data.fd, &ev, sizeof(ev));
            if (bytesRead == sizeof(ev)) {
                LOG(INFO) << "Event type: " << ev.type << ", code: " << ev.code << ", value: " << ev.value;
                uint32_t type = 0;
                InputEvent::GetInstance().HandleInputEvent(&ev, type);
            }
        }
    }

}

int InputEvent::LIDInit()
{
    LOG(INFO) << "LIDInit start";
    epollFd_  =  epoll_create1(0);
    DIR *dir = opendir(INPUT_DEVICES_PATH);
    if (dir == nullptr) {
        LOG(INFO) << "opendir err";
        return 0;
    }

    struct dirent *entry;
    while ((entry = readdir(dir)) != nullptr) {
        if (entry->d_name[0] == '.') continue;
        std::string devicePath = INPUT_DEVICES_PATH + std::string(entry->d_name);
        int inputFd = open(devicePath.c_str(), O_RDONLY);
        if (inputFd == -1) {
            continue;
        }
            // 添加到 epoll 监听
        epoll_event ev;
        ev.events = EPOLLIN;
        ev.data.fd = inputFd;
        if (epoll_ctl(epollFd_, EPOLL_CTL_ADD, inputFd, &ev) == -1) {
            close(inputFd);
            LOG(INFO) << "epoll_ctl err";
            continue;
        }

        inputFds_.push_back(inputFd);
    }
    thread_ = std::thread([this] { this->OnThread(); });
    OHOS::InputDeviceManager::GetInstance()->Add(&KeysInputDevice::GetInstance());
    addInputDeviceHelper_();
    LOG(INFO) << "add InputDevice done";

    return 0;
}

base/update/updater/services/ui/driver/input_event.h
 

class InputEvent {
    DISALLOW_COPY_MOVE(InputEvent);
public:
    void RegisterAddInputDeviceHelper(AddInputDeviceFunc ptr);
    void RegisterHandleEventHelper(HandlePointersEventFunc ptr);
    InputEvent() = default;
    ~InputEvent(); //+
    static InputEvent &GetInstance();
    int HandleInputEvent(const struct input_event *iev, uint32_t type);
    void GetInputDeviceType(uint32_t devIndex, uint32_t &type);
    static void ReportEventPkgCallback(const InputEventPackage **pkgs, const uint32_t count, uint32_t devIndex);
    /**
     * @brief Init input device driver.
     */
    int HdfInit(); //+
    int LIDInit(); //+
    void OnThread(); //+

private:
    IInputInterface *inputInterface_;
    InputEventCb callback_;
    std::unordered_map<uint32_t, uint32_t> devTypeMap_{};
    AddInputDeviceFunc addInputDeviceHelper_;
    HandlePointersEventFunc handlePointersEventHelper_;
    int32_t epollFd_ ; //+
    std::vector<int> inputFds_; //+
    std::thread thread_; //+
};

2.base/update/updater/services/ui/updater_ui_env.cpp
初始化对应功能

void UpdaterUiEnv::InitInputDriver()
{
    InputEvent::GetInstance().HdfInit();
    InputEvent::GetInstance().LIDInit(); //+
}

3.注意事项

可能会出现上报的POSITION不是触摸屏幕的实际坐标,需自行进行转换,如下图

正常上报触摸信息是触摸实际坐标就不用调整;

4.PointersInputDevice的回调
上报的触摸数据最后都会进入到HandleEvAbsMt里面装载

#如果有误还请大佬指出#

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐