OpenHarmony源码解析之源于wayland的输入系统
发布时间:2022-02-12 20:45:33 所属栏目:系统 来源:互联网
导读:在之前一篇文章《OpenHarmony 多模输入子系统源码分析之事件派发流程 接口说明》中分析的输入系统的逻辑的是基于openharmony L0系统的,而本篇文章是基于openharmony L2系统的,在L2系统中输入系统并不是由InputManagerService, InputEventHub, InputEventDi
在之前一篇文章《OpenHarmony 多模输入子系统源码分析之事件派发流程 & 接口说明》中分析的输入系统的逻辑的是基于openharmony L0系统的,而本篇文章是基于openharmony L2系统的,在L2系统中输入系统并不是由InputManagerService, InputEventHub, InputEventDistributer来负责处理的输入事件的,而是由第三方库wayland来负责处理输入事件的,所以本章内容就是分析基于wayland协议的输入系统。 输入系统框架 整个输入流程的派发过程: kernel ->HDF->uinput -> libinput –> weston -> wayland client -> wm -> ACE -> JS应用 当底层有事件发生的时候会通过驱动给HDF, 然后通过HDI接口给uinput,然后uinput会通过注入事件的方式把事件注入到libinput中,当libinput检测到有事件传上来的时候就会进行处理,处理完会给weston继续处理和派发,weston处理完后会通过wayland协议传给wayland client端,这是一个IPC调用,wayland处理完后会继续派发给windowmanager(简称wm),之后通过ACE传给JS应用。 输入系统事件派发流程 首先在device_info.hcs和input_config.hcs配置文件中配置相应的信息,多模输入系统的HdfDeviceEventManager会在启动的时候去bind对应的hdf service, 然后通过RegisterReportCallback去注册对应的回调函数。 foundationmultimodalinputinputuinputhdf_device_event_manager.cpp 复制 void HdfDeviceEventManager::ConnectHDFInit() { uint32_t ret = GetInputInterface(&inputInterface_); if (ret != 0) { HiLog::Error(LABEL, "Initialize %{public}s fail! ret is %{public}u", __func__, ret); return; } if (inputInterface_ == nullptr || inputInterface_->iInputManager == nullptr) { HiLog::Error(LABEL, "%{public}s inputInterface_ or iInputManager is NULL", __func__); return; } thread_ = std::thread(&InjectThread::InjectFunc, injectThread_); ret = inputInterface_->iInputManager->OpenInputDevice(TOUCH_DEV_ID); if ((ret == INPUT_SUCCESS) && (inputInterface_->iInputReporter != nullptr)) { ret = inputInterface_->iInputManager->GetInputDevice(TOUCH_DEV_ID, &iDevInfo_); if (ret != INPUT_SUCCESS) { HiLog::Error(LABEL, "%{public}s GetInputDevice error %{public}d", __func__, ret); return; } std::unique_ptr<HdfDeviceEventDispatch> hdf = std::make_unique<HdfDeviceEventDispatch>( iDevInfo_->attrSet.axisInfo[ABS_MT_POSITION_X].max, iDevInfo_->attrSet.axisInfo[ABS_MT_POSITION_Y].max); if (hdf == nullptr) { HiLog::Error(LABEL, "%{public}s hdf is nullptr", __func__); return; } callback_.EventPkgCallback = hdf->GetEventCallbackDispatch; ret = inputInterface_->iInputReporter->RegisterReportCallback(TOUCH_DEV_ID, &callback_); } } 当有事件上来的时候就会回调GetEventCallbackDispatch foundationmultimodalinputinputuinputhdf_device_event_dispatch.cpp 复制 void HdfDeviceEventDispatch::GetEventCallbackDispatch( const EventPackage **pkgs, uint32_t count, uint32_t devIndex) { if (pkgs == nullptr) { HiLog::Error(LABEL, " %{public}s fail! pkgs is nullptr", __func__); return; } for (uint32_t i = 0; i < count; i++) { if (pkgs[i] == nullptr) { continue; } if ((pkgs[i]->type == 0) && (pkgs[i]->code == 0) && (pkgs[i]->value == 0)) { InjectInputEvent injectInputSync = {injectThread_.TOUCH_SCREEN_DEVICE_ID, 0, SYN_MT_REPORT, 0}; injectThread_.WaitFunc(injectInputSync); } InjectInputEvent injectInputEvent = { injectThread_.TOUCH_SCREEN_DEVICE_ID, pkgs[i]->type, pkgs[i]->code, pkgs[i]->value }; injectThread_.WaitFunc(injectInputEvent); } } 然后通过InjectThread::WaitFunc准备对事件进行注入,在该函数中会通过notify_one来唤醒InjectFunc这个函数 foundationmultimodalinputinputuinputinject_thread.cpp 复制 void InjectThread::InjectFunc() const { std::unique_lock<std::mutex> uniqueLock(mutex_); while (true) { conditionVariable_.wait(uniqueLock); while (injectQueue_.size() > 0) { if (injectQueue_[0].deviceId == TOUCH_SCREEN_DEVICE_ID) { g_pTouchScreen->EmitEvent(injectQueue_[0].type, injectQueue_[0].code, injectQueue_[0].value); } else if (injectQueue_[0].deviceId == KEYBOARD_DEVICE_ID) { g_pKeyboard->EmitEvent(injectQueue_[0].type, injectQueue_[0].code, injectQueue_[0].value); } injectQueue_.erase(injectQueue_.begin()); } } } void InjectThread::WaitFunc(InjectInputEvent injectInputEvent) const { std::lock_guard<std::mutex> lockGuard(mutex_); injectQueue_.push_back(injectInputEvent); conditionVariable_.notify_one(); } 最终会调用VirtualDevice::EmitEvent, 在该函数中会将事件写入到uinput的设备文件中。 foundationmultimodalinputinputuinputvirtual_device.cpp 复制 fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK); 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, NULL); #endif if (write(fd_, &event, sizeof(event)) < static_cast<ssize_t>(sizeof(event))) { HiLog::Error(LABEL, "Event write failed %{public}s aborting", __func__); return false; } return true; } 当uinput有上报输入事件的时候,fd就会发生变化从而就会调用回调函数libinput_source_dispatch,再继续调用udev_input_dispatch,在udev_input_dispatch中再继续调用process_events。 third_partywestonlibwestonlibinput-seat.c 复制 static int udev_input_dispatch(struct udev_input *input) { if (libinput_dispatch(input->libinput) != 0) weston_log("libinput: Failed to dispatch libinputn"); process_events(input); return 0; } static int libinput_source_dispatch(int fd, uint32_t mask, void *data) { struct udev_input *input = data; return udev_input_dispatch(input) != 0; } 在process_events中会遍历每个event,然后调用process_event来处理每个event。 third_partywestonlibwestonlibinput-seat.c 复制 static void process_events(struct udev_input *input) { struct libinput_event *event; while ((event = libinput_get_event(input->libinput))) { process_event(event); // for multi model input. if (g_libinput_event_listener) { weston_log("process_events: call libinput_event_listener.n"); g_libinput_event_listener(event); } else { weston_log("process_events: libinput_event_listener is not set.n"); } libinput_event_destroy(event); } } 在process_event中,udev_input_process_event这个函数是处理设备的添加和删除,evdev_device_process_event_l这个函数是处理输入事件的。 third_partywestonlibwestonlibinput-seat.c 复制 static void process_event(struct libinput_event *event) { if (udev_input_process_event(event)) return; if (evdev_device_process_event_l(event)) return; } 在这个函数中会根据不同的事件类型调用不同事件类型的处理函数 third_partywestonlibwestonlibinput-device.c 复制 int evdev_device_process_event_l(struct libinput_event *event) { struct libinput_device *libinput_device = libinput_event_get_device(event); struct evdev_device *device = libinput_device_get_user_data(libinput_device); int handled = 1; bool need_frame = false; switch (libinput_event_get_type(event)) { case LIBINPUT_EVENT_KEYBOARD_KEY: handle_keyboard_key(libinput_device, libinput_event_get_keyboard_event(event)); break; case LIBINPUT_EVENT_POINTER_MOTION: need_frame = handle_pointer_motion(libinput_device, libinput_event_get_pointer_event(event)); break; case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE: need_frame = handle_pointer_motion_absolute( libinput_device, libinput_event_get_pointer_event(event)); break; case LIBINPUT_EVENT_POINTER_BUTTON: need_frame = handle_pointer_button(libinput_device, libinput_event_get_pointer_event(event)); break; case LIBINPUT_EVENT_POINTER_AXIS: need_frame = handle_pointer_axis( libinput_device, libinput_event_get_pointer_event(event)); break; case LIBINPUT_EVENT_TOUCH_DOWN: handle_touch_down(libinput_device, libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_MOTION: handle_touch_motion(libinput_device, libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_UP: handle_touch_up(libinput_device, libinput_event_get_touch_event(event)); break; case LIBINPUT_EVENT_TOUCH_FRAME: handle_touch_frame(libinput_device, libinput_event_get_touch_event(event)); break; default: handled = 0; weston_log("unknown libinput event %dn", libinput_event_get_type(event)); } if (need_frame) notify_pointer_frame(device->seat); return handled; } 先以key事件为例,看handle_keyboard_key这个函数,在这个函数中会获取按键的状态(按下和抬起),然后通过notify_key来派发事件。 (编辑:晋中站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |