在之前一篇文章《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_);
}
}
当有事件上来的时候就会回调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);
}
}
然后通过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();
}
最终会调用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;
}
当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;
}
在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);
}
}
在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;
}
在这个函数中会根据不同的事件类型调用不同事件类型的处理函数
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;
}
先以key事件为例,看handle_keyboard_key这个函数,在这个函数中会获取按键的状态(按下和抬起),然后通过notify_key来派发事件。
大型站长资讯类网站! https://www.0817zz.com