想了解更多关于开源的码解内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com
多模输入子系统是多模 OpenHarmony 输入事件管理框架。多模输入服务接收多种类型输入设备(触摸屏、输入鼠标、码解键盘、析之系统触摸板等)的多模输入事件,通过归一/标准化处理后,输入分发给多模客户端(应用,码解系统服务)。析之系统多模输入还提供事件注入接口,多模该接口目前仅对系统应用开放。
多模输入子系统分为框架部分和服务部分:框架部分封装了各种接口给其他子系统和应用来调用;服务部分实现了这些接口,并且实现了事件派发处理的核心逻辑。这两个部分运行在不同进程中,根据具体接口,通过socket或者binder ipc机制进行通信。
/foundation/multimodalinput/input
├── frameworks # napi接口代码,客户端实现代码
├── interfaces # 对外接口存放目录
│ └── native # 对外native层接口存放目录
│ └── innerkits # 对系统内部子系统提供native层接口存放目录
├── service # 服务端代码
├── sa_profile # 服务启动配置文件
├── tools # 输入事件注入工具
├── uinput # 输入事件注入模块
├── util # socket相关工具类
说明:
AceAbility::OnStart()方法中先调用基类Ability::OnStart()方法走完上述时序图的流程,然后调用如下代码段,创建AceWindowListener,并调用WindowImpl::SetInputEventConsumer()注册输入事件回调。
OHOS::sptr<OHOS::Rosen::Window> window = Ability::GetWindow();
std::shared_ptr<AceAbility> self = std::static_pointer_cast<AceAbility>(shared_from_this());
OHOS::sptr<AceWindowListener> aceWindowListener = new AceWindowListener(self);
// register surface change callback and window mode change callback
window->RegisterWindowChangeListener(aceWindowListener);
// register drag event callback
window->RegisterDragListener(aceWindowListener);
// register Occupied Area callback
window->RegisterOccupiedAreaChangeListener(aceWindowListener);
// register ace ability handler callback
window->SetAceAbilityHandler(aceWindowListener);
// register input consumer callback
std::shared_ptr<AceWindowListener> aceInputConsumer = std::make_shared<AceWindowListener>(self);
window->SetInputEventConsumer(aceInputConsumer);
说明:
void MMIService::OnThread()
{
SetThreadName(std::string("mmi_service"));
uint64_t tid = GetThisThreadId();
delegateTasks_.SetWorkerThreadId(tid);
MMI_HILOGI("Main worker thread start. tid:%{ public}" PRId64 "", tid);
#ifdef OHOS_RSS_CLIENT
tid_.store(tid);
#endif
libinputAdapter_.RetriggerHotplugEvents();
libinputAdapter_.ProcessPendingEvents();
while (state_ == ServiceRunningState::STATE_RUNNING) {
epoll_event ev[MAX_EVENT_SIZE] = { };
int32_t timeout = TimerMgr->CalcNextDelay();
MMI_HILOGD("timeout:%{ public}d", timeout);
int32_t count = EpollWait(ev[0], MAX_EVENT_SIZE, timeout, mmiFd_);
for (int32_t i = 0; i < count && state_ == ServiceRunningState::STATE_RUNNING; i++) {
auto mmiEd = reinterpret_cast<mmi_epoll_event*>(ev[i].data.ptr);
CHKPC(mmiEd);
if (mmiEd->event_type == EPOLL_EVENT_INPUT) {
libinputAdapter_.EventDispatch(ev[i]);//处理input事件
} else if (mmiEd->event_type == EPOLL_EVENT_SOCKET) {
OnEpollEvent(ev[i]);
} else if (mmiEd->event_type == EPOLL_EVENT_SIGNAL) {
OnSignalEvent(mmiEd->fd);
} else if (mmiEd->event_type == EPOLL_EVENT_ETASK) {
OnDelegateTask(ev[i]);
} else {
MMI_HILOGW("Unknown epoll event type:%{ public}d", mmiEd->event_type);
}
}
TimerMgr->ProcessTimers();
if (state_ != ServiceRunningState::STATE_RUNNING) {
break;
}
}
MMI_HILOGI("Main worker thread stop. tid:%{ public}" PRId64 "", tid);
}
说明:
MMIService收到libinput上报的input事件后,会调用InputEventHandler::OnEvent来处理输入事件。最终EventDispatchHandler通过socket把事件派发给目标应用进程。
多模服务端InputWindowsManager类中有如下成员变量。
DisplayGroupInfo displayGroupInfo_;
std::map<int32_t, WindowInfo> touchItemDownInfos_;
DisplayGroupInfo中包含了当前获焦的窗口id,以z轴排序的窗口信息列表,物理屏幕信息列表等。displayGroupInfo_信息由窗口管理服务调用。
MMI::InputManager::GetInstance()->UpdateDisplayInfo(displayGroupInfo_)接口设置。
struct DisplayGroupInfo {
int32_t width; //Width of the logical display
int32_t height; //Height of the logical display
int32_t focusWindowId; //ID of the focus window
//List of window information of the logical display arranged in Z order, with the top window at the top
std::vector<WindowInfo> windowsInfo;
std::vector<DisplayInfo> displaysInfo; //Physical screen information list
};
以键盘按键事件为例。
收到libinput上报的输入事件之后,最终走到EventDispatchHandler::DispatchKeyEventPid(UDSServer& udsServer, std::shared_ptr<KeyEvent> key)函数。
简化的调用流程如下:
EventDispatchHandler::DispatchKeyEventPid() =>
InputWindowsManager::UpdateTarget() =>
InputWindowsManager::GetPidAndUpdateTarget()
int32_t InputWindowsManager::GetPidAndUpdateTarget(std::shared_ptr<InputEvent> inputEvent)
{
CALL_DEBUG_ENTER;
CHKPR(inputEvent, INVALID_PID);
const int32_t focusWindowId = displayGroupInfo_.focusWindowId;
WindowInfo* windowInfo = nullptr;
for (auto &item : displayGroupInfo_.windowsInfo) {
if (item.id == focusWindowId) {
windowInfo = &item;
break;
}
}
CHKPR(windowInfo, INVALID_PID);
inputEvent->SetTargetWindowId(windowInfo->id);
inputEvent->SetAgentWindowId(windowInfo->agentWindowId);
MMI_HILOGD("focusWindowId:%{ public}d, pid:%{ public}d", focusWindowId, windowInfo->pid);
return windowInfo->pid;
}
InputWindowsManager::GetPidAndUpdateTarget()函数中把当前获焦windowId信息设置到InputEvent中,并且返回目标窗口所在进程pid,有了目标进程pid,就可以获取到目标进程对应的socket会话的服务端fd,把事件派发给目标进程。
touch事件目标窗口信息的获取和按键事件不同,感兴趣的可以自己查看代码。
本篇文章基于社区weekly_20230207的代码,对多模输入客户端注册监听流程和多模服务端事件派发流程作了简单介绍。相信大家通过本文,对多模输入子系统能有一个大致了解。
想了解更多关于开源的内容,请访问:
51CTO 开源基础软件社区
https://ost.51cto.com
责任编辑:jianghua 来源: 51CTO 开源基础软件社区 多模输入子系统鸿蒙(责任编辑:知识)
泰勒·斯威夫特照片被滥用,生成式AI让Deepfake变得廉价且简单
兴达国际(01899.HK)发布公告:预期2020年纯利同比减少50%
三六零发布2023年业绩预告:业绩大幅改善,亏损同比大幅收窄80%
*ST海航(600221.SH):2月客运量同比升419.17% 货邮载运率32.77%