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

系统 OpenHarmony
本篇文章是基于openharmony L2系统的,所以本章内容就是分析基于wayland协议的输入系统。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://harmonyos.51cto.com​

简介

在之前一篇文章《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去注册对应的回调函数。

foundation\multimodalinput\input\uinput\hdf_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_);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

当有事件上来的时候就会回调GetEventCallbackDispatch

foundation\multimodalinput\input\uinput\hdf_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);
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.

然后通过InjectThread::WaitFunc准备对事件进行注入,在该函数中会通过notify_one来唤醒InjectFunc这个函数

foundation\multimodalinput\input\uinput\inject_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();
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.

最终会调用VirtualDevice::EmitEvent, 在该函数中会将事件写入到uinput的设备文件中。

foundation\multimodalinput\input\uinput\virtual_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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

当uinput有上报输入事件的时候,fd就会发生变化从而就会调用回调函数libinput_source_dispatch,再继续调用udev_input_dispatch,在udev_input_dispatch中再继续调用process_events。

third_party\weston\libweston\libinput-seat.c

static int
udev_input_dispatch(struct udev_input *input)
{
  if (libinput_dispatch(input->libinput) != 0)
    weston_log("libinput: Failed to dispatch libinput\n");

  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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

在process_events中会遍历每个event,然后调用process_event来处理每个event。

third_party\weston\libweston\libinput-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);
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.

在process_event中,udev_input_process_event这个函数是处理设备的添加和删除,evdev_device_process_event_l这个函数是处理输入事件的。

third_party\weston\libweston\libinput-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;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

在这个函数中会根据不同的事件类型调用不同事件类型的处理函数

third_party\weston\libweston\libinput-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 %d\n",
         libinput_event_get_type(event));
  }

  if (need_frame)
    notify_pointer_frame(device->seat);

  return handled;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.

先以key事件为例,看handle_keyboard_key这个函数,在这个函数中会获取按键的状态(按下和抬起),然后通过notify_key来派发事件。

third_party\weston\libweston\libinput-device.c

static void
handle_keyboard_key(struct libinput_device *libinput_device,
        struct libinput_event_keyboard *keyboard_event)
{
  struct evdev_device *device =
    libinput_device_get_user_data(libinput_device);
  int key_state =
    libinput_event_keyboard_get_key_state(keyboard_event);
  int seat_key_count =
    libinput_event_keyboard_get_seat_key_count(keyboard_event);
  struct timespec time;

  /* Ignore key events that are not seat wide state changes. */
  if ((key_state == LIBINPUT_KEY_STATE_PRESSED &&
       seat_key_count != 1) ||
      (key_state == LIBINPUT_KEY_STATE_RELEASED &&
       seat_key_count != 0))
    return;

  timespec_from_usec(&time,
         libinput_event_keyboard_get_time_usec(keyboard_event));

  notify_key(device->seat, &time,
       libinput_event_keyboard_get_key(keyboard_event),
       key_state, STATE_UPDATE_AUTOMATIC);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

在notiyf_key这个函数中,会执行grab->interface->key,grab是指向weston_keyboard_grab这个结构体的函数指针,grab->interface->key其实就是调用default_grab_keyboard_key。

third_party\weston\libweston\input.c

WL_EXPORT void
notify_key(struct weston_seat *seat, const struct timespec *time, uint32_t key,
     enum wl_keyboard_key_state state,
     enum weston_key_state_update update_state)
{
  struct weston_compositor *compositor = seat->compositor;
  struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
  struct weston_keyboard_grab *grab = keyboard->grab;
  uint32_t *k, *end;

  if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
    weston_compositor_idle_inhibit(compositor);
  } else {
    weston_compositor_idle_release(compositor);
  }

  end = keyboard->keys.data + keyboard->keys.size;
  for (k = keyboard->keys.data; k < end; k++) {
    if (*k == key) {
      /* Ignore server-generated repeats. */
      if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
        return;
      *k = *--end;
    }
  }
  keyboard->keys.size = (void *) end - keyboard->keys.data;
  if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
    k = wl_array_add(&keyboard->keys, sizeof *k);
    *k = key;
  }

  if (grab == &keyboard->default_grab ||
      grab == &keyboard->input_method_grab) {
    weston_compositor_run_key_binding(compositor, keyboard, time,
              key, state);
    grab = keyboard->grab;
  }

  grab->interface->key(grab, time, key, state);

  if (keyboard->pending_keymap &&
      keyboard->keys.size == 0)
    update_keymap(seat);

  if (update_state == STATE_UPDATE_AUTOMATIC) {
    update_modifier_state(seat,
              wl_display_get_serial(compositor->wl_display),
              key,
              state);
  }

  keyboard->grab_serial = wl_display_get_serial(compositor->wl_display);
  if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
    keyboard->grab_time = *time;
    keyboard->grab_key = key;
  }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.

在default_grab_keyboard_key中会继续调用weston_keyboard_send_key。在wayland协议中,在Server和Client之间,对象是一一对应的,互相知道这个对象的状态。Client是 wl_proxy,与之对应的,在Server就会有一个 wl_resource。之后会遍历所有的wl_resource,然后调用各自的wl_keyboard_send_key。

third_party\weston\libweston\input.c

static void
default_grab_keyboard_key(struct weston_keyboard_grab *grab,
        const struct timespec *time, uint32_t key,
        uint32_t state)
{
  weston_keyboard_send_key(grab->keyboard, time, key, state);
}

WL_EXPORT void
weston_keyboard_send_key(struct weston_keyboard *keyboard,
       const struct timespec *time, uint32_t key,
       enum wl_keyboard_key_state state)
{
  struct wl_resource *resource;
  struct wl_display *display = keyboard->seat->compositor->wl_display;
  uint32_t serial;
  struct wl_list *resource_list;
  uint32_t msecs;

  if (!weston_keyboard_has_focus_resource(keyboard))
    return;

  resource_list = &keyboard->focus_resource_list;
  serial = wl_display_next_serial(display);
  msecs = timespec_to_msec(time);
  wl_resource_for_each(resource, resource_list) {
    send_timestamps_for_input_resource(resource,
               &keyboard->timestamps_list,
               time);
    wl_keyboard_send_key(resource, serial, msecs, key, state);
  }
};
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.

wl_keyboard_send_key其实会进行IPC调用,通过wayland协议,把server端的信息传给client端。Wayland核心协议是通过protocol/wayland.xml这个文件定义的。它通过wayland_scanner这个程序扫描后会生成wayland-protocol.c, wayland-client-protocol.h和wayland-server-protocol.h三个文件。wayland-client-protocol.h是给Client用的;wayland-server-protocol.h是给Server用的; wayland-protocol.c描述了接口,Client和Server都会用。根据wayland协议,这个函数会调用到服务端wayland-server的wl_resouce_post_event。

out\ohos-arm-release\gen\third_party\wayland_standard\protocol\wayland-server-protocol.h

static inline void
wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
{
  wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

在wl_resource_post_event中会继续调用wl_resource_post_event_array,在调用handle_array的时候会传入函数指针wl_closure_send。

third_party\wayland_standard\src\wayland-server.c

WL_EXPORT void
wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
           union wl_argument *args)
{
  handle_array(resource, opcode, args, wl_closure_send);
}

WL_EXPORT void
wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
{
  union wl_argument args[WL_CLOSURE_MAX_ARGS];
  struct wl_object *object = &resource->object;
  va_list ap;

  va_start(ap, opcode);
  wl_argument_from_va_list(object->interface->events[opcode].signature,
         args, WL_CLOSURE_MAX_ARGS, ap);
  va_end(ap);

  wl_resource_post_event_array(resource, opcode, args);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.

在handle_array中,会调用send_func这个函数指针说指向的函数,实际上就是调用wl_closure_send这个函数。

third_party\wayland_standard\src\wayland-server.c

static void
handle_array(struct wl_resource *resource, uint32_t opcode,
       union wl_argument *args,
       int (*send_func)(struct wl_closure *, struct wl_connection *))
{
  struct wl_closure *closure;
  struct wl_object *object = &resource->object;

  if (resource->client->error)
    return;

  if (!verify_objects(resource, opcode, args)) {
    resource->client->error = 1;
    return;
  }

  closure = wl_closure_marshal(object, opcode, args,
             &object->interface->events[opcode]);

  if (closure == NULL) {
    resource->client->error = 1;
    return;
  }

  log_closure(resource, closure, true);

  if (send_func(closure, resource->client->connection))
    resource->client->error = 1;

  wl_closure_destroy(closure);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

wl_connection代表Server与Client的连接,其中包含了in buffer和out buffer,分别作为输入和输出的缓冲区。在wl_closure_send这个函数中会调用wl_connection_write向wl_connection写入数据。

third_party\wayland_standard\src\connection.c

int
wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
{
  int size;
  uint32_t buffer_size;
  uint32_t *buffer;
  int result;

  if (copy_fds_to_connection(closure, connection))
    return -1;

  buffer_size = buffer_size_for_closure(closure);
  buffer = zalloc(buffer_size * sizeof buffer[0]);
  if (buffer == NULL)
    return -1;

  size = serialize_closure(closure, buffer, buffer_size);
  if (size < 0) {
    free(buffer);
    return -1;
  }

  result = wl_connection_write(connection, buffer, size);
  free(buffer);

  return result;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.

在该函数中会通过wl_connection_flush向Client发送数据, 把connection中out buffer的request通过socket发出去

third_party\wayland_standard\src\connection.c

int
wl_connection_write(struct wl_connection *connection,
        const void *data, size_t count)
{
  if (connection->out.head - connection->out.tail +
      count > ARRAY_LENGTH(connection->out.data)) {
    connection->want_flush = 1;
    if (wl_connection_flush(connection) < 0)
      return -1;
  }

  if (wl_buffer_put(&connection->out, data, count) < 0)
    return -1;

  connection->want_flush = 1;

  return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.

那么,Client是怎么读取和处理这些event呢? 首先Client端需要监听这个wl_proxy,这是通过调用wl_registry_add_listener()->wl_proxy_add_listener()设置的。然后在Client的主循环中会调用wl_display_dispatch,并在wl_display_dispatch_queue()中处理收到的event和发出out buffer中的request。在wl_display_dispatch_queue中,wl_display_read_events负责 从connection的in buffer中读出数据,转为wl_closure,插入到queue->event_list,等待后续处理。接着会调用wl_display_dispatch_queue_pending。

third_party\wayland_standard\src\wayland-client.c

WL_EXPORT int
wl_display_dispatch(struct wl_display *display)
{
  return wl_display_dispatch_queue(display, &display->default_queue);
}

WL_EXPORT int
wl_display_dispatch_queue(struct wl_display *display,
        struct wl_event_queue *queue)
{
  int ret;

  if (wl_display_prepare_read_queue(display, queue) == -1)
    return wl_display_dispatch_queue_pending(display, queue);

  while (true) {
    ret = wl_display_flush(display);

    if (ret != -1 || errno != EAGAIN)
      break;

    if (wl_display_poll(display, POLLOUT) == -1) {
      wl_display_cancel_read(display);
      return -1;
    }
  }

  /* Don't stop if flushing hits an EPIPE; continue so we can read any
   * protocol error that may have triggered it. */
  if (ret < 0 && errno != EPIPE) {
    wl_display_cancel_read(display);
    return -1;
  }

  if (wl_display_poll(display, POLLIN) == -1) {
    wl_display_cancel_read(display);
    return -1;
  }

  if (wl_display_read_events(display) == -1)
    return -1;

  return wl_display_dispatch_queue_pending(display, queue);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.

在该函数中继续调用dispatch_queue。

third_party\wayland_standard\src\wayland-client.c

WL_EXPORT int
wl_display_dispatch_queue_pending(struct wl_display *display,
          struct wl_event_queue *queue)
{
  int ret;

  pthread_mutex_lock(&display->mutex);

  ret = dispatch_queue(display, queue);

  pthread_mutex_unlock(&display->mutex);

  return ret;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

在该函数中会将前面插入到queue当中的event(wl_closure)依次拿出来处理调用dispatch_event。

third_party\wayland_standard\src\wayland-client.c

static int
dispatch_queue(struct wl_display *display, struct wl_event_queue *queue)
{
  int count;

  if (display->last_error)
    goto err;

  count = 0;
  while (!wl_list_empty(&display->display_queue.event_list)) {
    dispatch_event(display, &display->display_queue);
    if (display->last_error)
      goto err;
    count++;
  }

  while (!wl_list_empty(&queue->event_list)) {
    dispatch_event(display, queue);
    if (display->last_error)
      goto err;
    count++;
  }

  return count;

err:
  errno = display->last_error;

  return -1;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

在该函数中最后通过wl_closure_invoke()进行调用。

third_party\wayland_standard\src\wayland-client.c

static void
dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
{
  struct wl_closure *closure;
  struct wl_proxy *proxy;
  int opcode;
  bool proxy_destroyed;

  closure = wl_container_of(queue->event_list.next, closure, link);
  wl_list_remove(&closure->link);
  opcode = closure->opcode;

  /* Verify that the receiving object is still valid by checking if has
   * been destroyed by the application. */
  validate_closure_objects(closure);
  proxy = closure->proxy;
  proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
  if (proxy_destroyed) {
    destroy_queued_closure(closure);
    return;
  }

  pthread_mutex_unlock(&display->mutex);

  if (proxy->dispatcher) {
    if (debug_client)
      wl_closure_print(closure, &proxy->object, false);

    wl_closure_dispatch(closure, proxy->dispatcher,
            &proxy->object, opcode);
  } else if (proxy->object.implementation) {
    if (debug_client)
      wl_closure_print(closure, &proxy->object, false);

    wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
          &proxy->object, opcode, proxy->user_data);
  }

  pthread_mutex_lock(&display->mutex);

  destroy_queued_closure(closure);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.

wl_closure_invoke其实是回调implementation指向的回调函数

third_party\wayland_standard\src\connection.c

void
wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
      struct wl_object *target, uint32_t opcode, void *data)
{
  int count;
  ffi_cif cif;
  ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2];
  void * ffi_args[WL_CLOSURE_MAX_ARGS + 2];
  void (* const *implementation)(void);

  count = arg_count_for_signature(closure->message->signature);

  ffi_types[0] = &ffi_type_pointer;
  ffi_args[0] = &data;
  ffi_types[1] = &ffi_type_pointer;
  ffi_args[1] = &target;

  convert_arguments_to_ffi(closure->message->signature, flags, closure->args,
         count, ffi_types + 2, ffi_args + 2);

  ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
         count + 2, &ffi_type_void, ffi_types);

  implementation = target->implementation;
  // OHOS fix: if listener function is not NULL, it will be call
  if (implementation[opcode]) {
    ffi_call(&cif, implementation[opcode], NULL, ffi_args);
  }

  wl_closure_clear_fds(closure);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.

在RegisterKeyboardListener中注册了各种回调函数OnKeyboardKeymap,OnKeyboardEnter,OnKeyboardLeave,OnKeyboardKey,OnKeyboardModifiers,OnKeyboardRepeatInfo。

foundation\graphic\standard\frameworks\wm\src\input_listener_manager.cpp

void InputListenerManager::RegisterKeyboardListener(uint32_t caps)
{
    bool haveKeyboardCapability = !!(caps & WL_SEAT_CAPABILITY_KEYBOARD);
    if (haveKeyboardCapability == true && keyboard == nullptr) {
        static struct wl_keyboard_listener listener = {
            OnKeyboardKeymap,
            OnKeyboardEnter,
            OnKeyboardLeave,
            OnKeyboardKey,
            OnKeyboardModifiers,
            OnKeyboardRepeatInfo,
        };

        keyboard = wl_seat_get_keyboard(seat);
        if (keyboard) {
            if (g_PowerKeyHandler == nullptr) {
                std::shared_ptr<AppExecFwk::EventRunner> powerKeyRunner =
                        AppExecFwk::EventRunner::Create(GLOBAL_ACTION_THREAD_NAME);
                g_PowerKeyHandler = std::make_shared<AppExecFwk::EventHandler>(powerKeyRunner);
                powerKeyRunner->Run();
            }
            wl_keyboard_add_listener(keyboard, &listener, nullptr);
        }
    }

    if (haveKeyboardCapability == false && keyboard != nullptr) {
        wl_keyboard_destroy(keyboard);
        keyboard = nullptr;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.

这些回调函数要被调用,首先Client端需要监听这个wl_proxy,这时InputListenerManager通过RegisterKeyboardListener将回调函数注册到listener中,然后再调用wl_keyboard_add_listener。

out\ohos-arm-release\gen\third_party\wayland_standard\protocol\wayland-client-protocol.h

static inline int
wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard,
       const struct wl_keyboard_listener *listener, void *data)
{
  return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard,
             (void (**)(void)) listener, data);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

这是会通过wl_proxy_add_listener将回调函数放入到proxy->object.implementation中。也就是说wanland client接收到事件后最终会回调InputListenerManager注册的回调函数。

third_party\wayland_standard\src\wayland-client.c

WL_EXPORT int
wl_proxy_add_listener(struct wl_proxy *proxy,
          void (**implementation)(void), void *data)
{
  if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
    wl_abort("Proxy %p is a wrapper\n", proxy);

  if (proxy->object.implementation || proxy->dispatcher) {
    wl_log("proxy %p already has listener\n", proxy);
    return -1;
  }

  proxy->object.implementation = implementation;
  proxy->user_data = data;

  return 0;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

现在再看回调函数OnKeyboardKey,接着调用listener->keyboardKey。

foundation\graphic\standard\frameworks\wm\src\input_listener_manager.cpp

void OnKeyboardKey(void *, struct wl_keyboard *,
                   uint32_t serial, uint32_t time, uint32_t key, uint32_t s)
{
    auto state = static_cast<KeyboardKeyState>(s);

    // Handle Power key
    WMLOGFD("key: %{public}d, state: %{public}d", key, state);
    if (key == KEY_POWER && g_PowerKeyHandler != nullptr) {
        HandlePowerKey(time, key, state);
        return;
    }

    const auto &inputListeners = g_getFocus();
    for (const auto &listener : inputListeners) {
        if (listener->keyboardKey) {
            listener->keyboardKey(listener->GetWindow(), serial, time, key, state);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

从这个添加监听的函数可以看出,当调用keyboardKey的时候会调用KeyboardHandleKey。

foundation\graphic\standard\frameworks\wm\src\multimodal_listener_manager.cpp

sptr<MultimodalListener> MultimodalListenerManager::AddListener(void *window)
{
    auto l = delegator.Dep<InputListenerManager>()->AddListener(window);
    sptr<MultimodalListener> ml = new MultimodalListener(window);
    ml->input = l;

    l->pointerMotion = std::bind(&MultimodalListenerManager::PointerHandleMotion, this, POINTER_ENTER_ARG);
    l->pointerButton = std::bind(&MultimodalListenerManager::PointerHandleButton, this, POINTER_BUTTON_ARG);
    l->pointerFrame = std::bind(&MultimodalListenerManager::PointerHandleFrame, this, POINTER_FRAME_ARG);
    l->pointerAxis = std::bind(&MultimodalListenerManager::PointerHandleAxis, this, POINTER_AXIS_ARG);
    l->keyboardKey = std::bind(&MultimodalListenerManager::KeyboardHandleKey, this, KEYBOARD_KEY_ARG);
    l->touchDown = std::bind(&MultimodalListenerManager::TouchHandleDown, this, TOUCH_DOWN_ARG);
    l->touchUp = std::bind(&MultimodalListenerManager::TouchHandleUp, this, TOUCH_UP_ARG);
    l->touchMotion = std::bind(&MultimodalListenerManager::TouchHandleMotion, this, TOUCH_MOTION_ARG);
    l->touchFrame = std::bind(&MultimodalListenerManager::TouchHandleFrame, this, TOUCH_FRAME_ARG);
    l->touchShape = std::bind(&MultimodalListenerManager::TouchHandleShape, this, TOUCH_SHAPE_ARG);
    l->touchOrientation = std::bind(
        &MultimodalListenerManager::TouchHandleOrientation, this, TOUCH_ORIENTATION_ARG);

    if (windowCallback.find(window) == windowCallback.end()) {
        windowCallback[window] = std::vector<sptr<MultimodalListener>>();
    }

    windowCallback[window].push_back(ml);
    return ml;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

在KeyboardHandleKey中会对按键信息进行处理,并且会把按键状态,键值,按键按下的时长这些值放入到KeyProperty结构体中,然后把KeyProperty封装成KeyEvent的数据结构中用于派发。

foundation\graphic\standard\frameworks\wm\src\multimodal_listener_manager.cpp

void MultimodalListenerManager::KeyboardHandleKey(void *data,
    uint32_t serial, uint32_t time, uint32_t key, KeyboardKeyState state)
{
    KeyEvent event;
    struct MultimodalProperty multiProperty = {
        .highLevelEvent = 0,
        .uuid = "",
        .sourceType = MultimodalEvent::KEYBOARD,
        .occurredTime = time,
        .deviceId = "",
        .inputDeviceId = 0,
        .isHighLevelEvent = false,
    };
    struct KeyProperty keyProperty = {
        .isPressed = (state == KEYBOARD_KEY_STATE_PRESSED),
        .keyCode = key,
        .keyDownDuration = 0,
    };

    static uint32_t keyDownTime = 0;
    if (state == KEYBOARD_KEY_STATE_PRESSED) {
        keyDownTime = time;
    } else {
        keyProperty.keyDownDuration = time - keyDownTime;
    }

    constexpr uint32_t linuxKeyBack = 158;
    if (key == linuxKeyBack) {
        keyProperty.keyCode = KeyEvent::CODE_BACK;
    }

    event.Initialize(multiProperty, keyProperty);
    const auto &mls = GetInputCallback(data);
    for (const auto &ml : mls) {
        if (ml->keyboardKeyCb) {
            ml->keyboardKeyCb(event);
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

由于目前openharmony代码在ACE部分没有完全支持对按键事件的处理,所以下面分析对touch事件的处理。现在也可以看TouchHandleUp这个回调,这个函数会调用ml->onTouchCb,

foundation\graphic\standard\frameworks\wm\src\multimodal_listener_manager.cpp

void MultimodalListenerManager::TouchHandleUp(void *data, uint32_t serial, uint32_t time, int32_t id)
{
    if (id < MAX_TOUCH_NUM) {
        actionEventInfo.touchCount--;
        actionEventInfo.isUp = true;
        actionEventInfo.touchEventInfos[id].isRefreshed = true;
        actionEventInfo.touchEventInfos[id].serial = serial;
        actionEventInfo.touchEventInfos[id].currentTime = time;
    }
    void *window = nullptr;
    if (id < MAX_TOUCH_NUM) {
        window = touchWindows[id];
        touchWindows[id] = nullptr;
    }
    WMLOGFD("window: %{public}p", window);

    while (actionEventInfo.isUp || actionEventInfo.isDown || actionEventInfo.isMotion) {
        TouchEvent touchEvent;
        TouchEventEncap(actionEventInfo, touchEvent, MAX_TOUCH_NUM);

        const auto &mls = GetInputCallback(data);
        for (const auto &ml : mls) {
            if (ml->onTouchCb) {
                ml->onTouchCb(touchEvent);
            }
        }
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.

通过RegistOnTouchCb注册的方式,最终会调用aceView->DispatchTouchEvent。

foundation\graphic\standard\frameworks\wm\src\client\window_manager_controller_client.cpp

void LayerControllerClient::RegistOnTouchCb(int id, funcOnTouch cb)
{
    LOCK(mutex);
    WMLOG_I("LayerControllerClient::%{public}s", __func__);
    if (cb) {
        WMLOG_I("LayerControllerClient::RegistOnTouchCb OK");
        GET_WINDOWINFO_VOID(windowInfo, id);
        windowInfo->mmiListener->onTouchCb = cb;
    }
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

foundation\graphic\standard\frameworks\wm\src\client\window_manager.cpp

void Window::RegistOnTouchCb(funcOnTouch cb)
{
    WMLOG_I("Window::RegistOnTouchCb start, windowid %{public}d", this->m_windowid);
    LayerControllerClient::GetInstance()->RegistOnTouchCb(m_windowid, cb);
    WMLOG_I("Window::RegistOnTouchCb end windowid %{public}d", this->m_windowid);
}

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.

foundation\ace\ace_engine\adapter\ohos\cpp\ace_ability.cpp

   auto&& touchEventCallback = [aceView = flutterAceView](OHOS::TouchEvent event) -> bool {
        LOGD("RegistOnTouchCb touchEventCallback called");
        return aceView->DispatchTouchEvent(aceView, event);
    };
    window->OnTouch(touchEventCallback);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

在DispatchTouchEvent中,会根据事件类型分为mouse event和touch event,这里先分析touch event,所以最后会调用ProcessTouchEvent。

foundation\ace\ace_engine\adapter\ohos\cpp\flutter_ace_view.cpp

bool FlutterAceView::DispatchTouchEvent(FlutterAceView* view, OHOS::TouchEvent& touchEvent)
{
    if (touchEvent.GetAction() == OHOS::TouchEvent::OTHER && touchEvent.GetSourceDevice() == OHOS::TouchEvent::MOUSE) {
        // mouse event
        std::shared_ptr<MultimodalEvent> multimodalEvent = touchEvent.GetMultimodalEvent();
        OHOS::MouseEvent* mouseEvent = (OHOS::MouseEvent*)multimodalEvent.get();
        if (mouseEvent == nullptr) {
            LOGE("mouseEvent is nullptr");
            return false;
        }
        LOGI("DispatchTouchEvent MouseEvent");
        view->ProcessMouseEvent(*mouseEvent);
    } else {
        // touch event
        LOGI("DispatchTouchEvent TouchEvent");
        return view->ProcessTouchEvent(touchEvent);
    }
    return true;
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

执行touchEventCallback_ 函数指针指向的函数,继续看touchEventCallback_ 指向了哪个函数。

foundation\ace\ace_engine\adapter\ohos\cpp\flutter_ace_view.cpp

bool FlutterAceView::ProcessTouchEvent(OHOS::TouchEvent& touchEvent)
{
    TouchPoint touchPoint = ConvertTouchEvent(touchEvent);
    bool forbiddenToPlatform = false;
    if (touchPoint.type != TouchType::UNKNOWN) {
        if (touchEventCallback_) {
            touchEventCallback_(touchPoint);
        }
    } else {
        LOGW("Unknown event.");
    }

#ifdef WEARABLE_PRODUCT
    forbiddenToPlatform = forbiddenToPlatform || IsNeedForbidToPlatform(point);
#endif

    // if last page, let os know so that to quit app.
    return forbiddenToPlatform || (!IsLastPage());
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.

看来touchEventCallback_是指向了RegisterTouchEventCallback通过参数穿过来的callback, 那继续看调用RegisterTouchEventCallback的callback是什么。

foundation\ace\ace_engine\adapter\ohos\cpp\flutter_ace_view.cpp

void FlutterAceView::RegisterTouchEventCallback(TouchEventCallback&& callback)
{
    ACE_DCHECK(callback);
    touchEventCallback_ = std::move(callback);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

在AceContainer::InitializeCallback中可以看出,最终这个callback就是执行pipeline_context的OnTouchEvent。

foundation\ace\ace_engine\adapter\ohos\cpp\ace_container.cpp

void AceContainer::InitializeCallback()
{
    ACE_FUNCTION_TRACE();

    ACE_DCHECK(aceView_ && taskExecutor_ && pipelineContext_);
    auto&& touchEventCallback = [context = pipelineContext_](const TouchPoint& event) {
        context->GetTaskExecutor()->PostTask(
            [context, event]() { context->OnTouchEvent(event); }, TaskExecutor::TaskType::UI);
    };
    aceView_->RegisterTouchEventCallback(touchEventCallback);
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.

在这个函数中最终会调用eventManager_.DispatchTouchEvent。之后就会通过ACE的接口把事件传给应用端。

foundation\ace\ace_engine\frameworks\core\pipeline\pipeline_context.cpp

void PipelineContext::OnTouchEvent(const TouchPoint& point)
{
    CHECK_RUN_ON(UI);
    ACE_FUNCTION_TRACE();
    if (!rootElement_) {
        LOGE("root element is nullptr");
        return;
    }
    auto scalePoint = point.CreateScalePoint(viewScale_);
    if (scalePoint.type == TouchType::DOWN) {
        LOGD("receive touch down event, first use touch test to collect touch event target");
        TouchRestrict touchRestrict { TouchRestrict::NONE };
        auto frontEnd = GetFrontend();
        if (frontEnd && (frontEnd->GetType() == FrontendType::JS_CARD)) {
            touchRestrict.UpdateForbiddenType(TouchRestrict::LONG_PRESS);
        }
        eventManager_.TouchTest(scalePoint, rootElement_->GetRenderNode(), touchRestrict);
    }
    if (scalePoint.type == TouchType::MOVE) {
        isMoving_ = true;
    }
    if (isKeyEvent_) {
        SetIsKeyEvent(false);
    }
    eventManager_.DispatchTouchEvent(scalePoint);
}
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.

总结

通过本篇文章的学习可以了解OpenHarmony L2系统基于wayland三方库的事件处理派发流程。

​想了解更多内容,请访问:​

​51CTO和华为官方合作共建的鸿蒙技术社区​

​https://harmonyos.51cto.com​

责任编辑:jianghua 来源: 鸿蒙社区
相关推荐

2023-04-06 09:14:11

多模输入子系统鸿蒙

2023-04-12 15:31:11

系统服务管理鸿蒙

2021-11-08 15:04:47

鸿蒙HarmonyOS应用

2022-02-17 20:57:07

OpenHarmon操作系统鸿蒙

2021-12-17 16:42:09

鸿蒙HarmonyOS应用

2022-01-06 16:17:58

鸿蒙HarmonyOS应用

2021-09-18 14:40:37

鸿蒙HarmonyOS应用

2023-06-28 15:00:02

开源鸿蒙输入系统架构

2022-01-10 15:30:11

鸿蒙HarmonyOS应用

2022-02-14 14:47:11

SystemUIOpenHarmon鸿蒙

2021-09-17 14:38:58

鸿蒙HarmonyOS应用

2022-05-10 11:17:27

电话子系统数据服务模块

2022-05-17 10:42:36

reboot源码解析

2021-11-18 10:28:03

鸿蒙HarmonyOS应用

2022-05-24 15:46:51

Wi-FiSTA模式

2022-06-13 14:18:39

电源管理子系统耗电量服务

2021-09-16 15:08:08

鸿蒙HarmonyOS应用

2022-05-20 10:32:49

事件循环器事件队列鸿蒙

2021-11-25 09:54:54

鸿蒙HarmonyOS应用

2021-12-08 15:07:51

鸿蒙HarmonyOS应用
点赞
收藏

51CTO技术栈公众号