加入收藏 | 设为首页 | 会员中心 | 我要投稿 源码网 (https://www.900php.com/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 服务器 > 系统 > 正文

OpenHarmony源码解析之源于wayland的输入系统

发布时间:2022-02-10 14:21:25 所属栏目:系统 来源:互联网
导读:在之前一篇文章《OpenHarmony 多模输入子系统源码分析之事件派发流程 接口说明》中分析的输入系统的逻辑的是基于openharmony L0系统的,而本篇文章是基于openharmony L2系统的,在L2系统中输入系统并不是由InputManagerService, InputEventHub, InputEvent
  在之前一篇文章《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来派发事件。

(编辑:源码网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读