OpenHarmony 源码解析之多模输入子系统(事件派发流程)

系统
本文可以了解多模输入系统事件派发的流程,以及多模输入系统的接口和注入事件的流程,结合以上的源码分析会对多模输入子系统会有更深入的理解。

[[424563]]

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

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

https://harmonyos.51cto.com

简介

多模输入系统主要用于接收按键,触摸等输入事件,并且会对这些原始输入事件进行处理,之后再对这些事件进行派发。同时多模输入系统还提供了注入事件的接口,应用可以通过调用这个接口产生输入事件,然后将该输入事件注入到输入系统中进行处理。

OpenHarmony 源码解析之多模输入子系统(事件派发流程)-鸿蒙HarmonyOS技术社区

输入系统框架

OpenHarmony 源码解析之多模输入子系统(事件派发流程)-鸿蒙HarmonyOS技术社区

多模输入系统主要是由InputManagerService, InputEventHub, InputEventDistributer来负责处理的。InputManagerService会启动InputEventHub,并且会通过创建子线程的方式来创建InputEventDistributer。当底层传来按键或触摸事件的时候,InputEventHub就会进行读取,并且会对这些原始的输入事件进行处理,处理完后会交给InputEventDistributer进行派发。InputEventDistributer又会通过InputEventClientProxy进行IPC交互的方式发给应用端。

多模输入系统事件派发流程

事件派发流程图

OpenHarmony 源码解析之多模输入子系统(事件派发流程)-鸿蒙HarmonyOS技术社区

源码分析

下面就对多模输入系统事件派发流程的源码进行分析。

InputManagerService

\foundation\graphic\wms\services\wms\wms.cpp

  1. int main() 
  2.     DEBUG_PERFORMANCE_REGISTER_SIG(); 
  3.     OHOS::HiFbdevInit(); 
  4.     OHOS::GfxEngines::GetInstance()->InitDriver(); 
  5.     HOS_SystemInit(); 
  6.     OHOS::InputManagerService::GetInstance()->Run(); 
  7.     while (1) { 
  8.         DEBUG_PERFORMANCE_PRINT_RESULT(); 
  9.         OHOS::LiteWM::GetInstance()->MainTaskHandler(); 
  10.         usleep(WMS_MAIN_TASK_PERIOD_IN_US); 
  11.     } 

InputManagerService的启动是在WMS的main函数中通过InputManagerService::GetInstance()->Run()执行的。

\foundation\graphic\wms\services\ims\input_manager_service.cpp

  1. void InputManagerService::Run() 
  2.     hub_ = InputEventHub::GetInstance(); 
  3.  
  4.     hub_->RegisterReadCallback(ReadCallback); 
  5.     hub_->SetUp(); 
  6.     distributerThreadCreated_ = pthread_create(&distributerThread_, nullptr, Distribute, nullptr); 
  7.     if (!distributerThreadCreated_) { 
  8.         pthread_detach(distributerThread_); 
  9.     } 

在InputManagerService::Run()中首先会创建InputEventHub的对象并通过RegisterReadCallback来注册InputEventHub的回调,然后通过SetUp来启动InputEventHub, InputEventHub主要是用于对底层原始输入事件的读取和处理,该函数的最后会创建distributerThread子线程,用于对输入事件的派发。

InputEventHub

\foundation\graphic\wms\services\ims\input_event_hub.cpp

  1. void InputEventHub::SetUp() 
  2.     int32_t ret = GetInputInterface(&inputInterface_); 
  3.     if (ret != INPUT_SUCCESS) { 
  4.         GRAPHIC_LOGE("get input driver interface failed!"); 
  5.         return
  6.     } 
  7.     uint8_t num = ScanInputDevice(); 
  8.     if (num == 0) { 
  9.         GRAPHIC_LOGE("There is no device!"); 
  10.         return
  11.     } 
  12.     for (uint8_t i = 0; i < num; i++) { 
  13.         if (inputInterface_ == nullptr || inputInterface_->iInputManager == nullptr) { 
  14.             GRAPHIC_LOGE("input interface or input manager is nullptr, open device failed!"); 
  15.             return
  16.         } 
  17.         ret = inputInterface_->iInputManager->OpenInputDevice(mountDevIndex_[i]); 
  18.         if (ret == INPUT_SUCCESS && inputInterface_->iInputReporter != nullptr) { 
  19.             callback_.EventPkgCallback = EventCallback; 
  20.             ret = inputInterface_->iInputReporter->RegisterReportCallback(mountDevIndex_[i], &callback_); 
  21.             if (ret != INPUT_SUCCESS) { 
  22.                 GRAPHIC_LOGE("device dose not exist, can't register callback to it!"); 
  23.                 return
  24.             } 
  25.             openDev_ = openDev_ | (1 << i); 
  26.         } 
  27.     } 

在这个函数中InputEventHub主要的工作就是通过调用驱动层的OpenInputDevice来打开输入设备,并且会将EventCallback的回调函数通过驱动层的RegisterReportCallback进行注册。当底层有事件传递上来,EventCallback就会被调用。OpenInputDevice和RegisterReportCallback具体实现分别是在drivers/peripheral/input/hal/src/input_manager.c和drivers/peripheral/input/hal/src/input_reporter.c中。

\foundation\graphic\wms\services\ims\input_event_hub.cpp

  1. void InputEventHub::EventCallback(const EventPackage **pkgs, uint32_t count, uint32_t devIndex) 
  2.     if (pkgs == nullptr || readCallback_ == nullptr || count == 0) { 
  3.         return
  4.     } 
  5.  
  6.     RawEvent& data = InputEventHub::GetInstance()->data_; 
  7.     for (uint32_t i = 0; i < count; i++) { 
  8.         if (pkgs[i]->type == EV_REL) { 
  9.             data.type = InputDevType::INDEV_TYPE_MOUSE; 
  10.             if (pkgs[i]->code == REL_X) 
  11.                 data.x += pkgs[i]->value; 
  12.             else if (pkgs[i]->code == REL_Y) 
  13.                 data.y += pkgs[i]->value; 
  14.         } else if (pkgs[i]->type == EV_ABS) { 
  15.             data.type = InputDevType::INDEV_TYPE_TOUCH; 
  16.             if (pkgs[i]->code == ABS_MT_POSITION_X) 
  17.                 data.x = pkgs[i]->value; 
  18.             else if (pkgs[i]->code == ABS_MT_POSITION_Y) 
  19.                 data.y = pkgs[i]->value; 
  20.         } else if (pkgs[i]->type == EV_KEY) { 
  21.             if (pkgs[i]->code == BTN_MOUSE || pkgs[i]->code == BTN_TOUCH) { 
  22.                 if (pkgs[i]->value == 0) 
  23.                     data.state = 0; 
  24.                 else if (pkgs[i]->value == 1) 
  25.                     data.state = 1; 
  26.             } 
  27.         } else if (pkgs[i]->type == EV_SYN) { 
  28.             if (pkgs[i]->code == SYN_REPORT) { 
  29.                 break; 
  30.             } 
  31.         } 
  32.     } 
  33.  
  34.     readCallback_(&data); 

当底层有输入事件上来的话,EventCallback就会被调用,在这个函数里会通过EventPackage->type来判断输入事件的类型,其中

EV_REL是相对坐标的输入事件,比如轨迹球,鼠标事件

EV_ABS是绝对坐标的输入事件,比如触屏触摸事件

EV_KEY是按键输入事件,比如设备上的物理按键的点击事件

EV_SYN是Motion的一系列动作结束标志位

如果是鼠标事件,会将相对坐标值放入到data.x和data.y中,如果是触屏触摸事件,会将在触屏上触摸的坐标位置放入到data.x和data.y中,如果是按键事件会将按键的点击状态放入到data.state中。

处理完输入事件后,会将数据放入到data中,并通过readCallback传给InputManagerService进行处理,之后就会调用InputManagerService::ReadCallback。

\foundation\graphic\wms\services\ims\input_manager_service.cpp

  1. void InputManagerService::ReadCallback(const RawEvent* event) 
  2.     if (event == nullptr) { 
  3.         return
  4.     } 
  5.     pthread_mutex_lock(&lock_); 
  6.     while (eventQueue_.size() == MAX_EVENT_SIZE) { 
  7.         pthread_cond_wait(&nonFull_, &lock_); 
  8.     } 
  9.     // push events into queue 
  10.     eventQueue_.push(event[0]); 
  11.     pthread_mutex_unlock(&lock_); 
  12.     pthread_cond_signal(&nonEmpty_); 
  13.  
  14. void* InputManagerService::Distribute(void* args) 
  15.     GRAPHIC_LOGI("InputManagerService::Distribute Ready to read distribute!"); 
  16.     while (true) { 
  17.         pthread_mutex_lock(&lock_); 
  18.         while (eventQueue_.size() == 0) { 
  19.             pthread_cond_wait(&nonEmpty_, &lock_); 
  20.         } 
  21.         // pop events from queue 
  22.         RawEvent events[MAX_INPUT_DEVICE_NUM]; 
  23.         int32_t len = (eventQueue_.size() > MAX_EVENT_SIZE) ? MAX_EVENT_SIZE : eventQueue_.size(); 
  24.         for (int32_t i = 0; i < len; i++) { 
  25.             events[i] = eventQueue_.front(); 
  26.             eventQueue_.pop(); 
  27.         } 
  28.         distributer_.Distribute(events, len); 
  29.         pthread_mutex_unlock(&lock_); 
  30.         pthread_cond_signal(&nonFull_); 
  31.     } 
  32.     return nullptr; 

ReadCallback这个函数首先会判断eventQueue这个事件队列里事件数量是否达到最大数量,如果达到最大数量该线程就一直等待,否则就会把该事件放到eventQueue这个事件队列里,并且同时也会发出nonEmpty的signal, 来让Distribute中的线程停止等待。

Distribute函数中,当eventQueue队列里没有事件的时候,就会一直等待,当有事件来的时候就会停止线程等待,然后会遍历整个eventQueue这个队列,把每个事件获取出来后放入到events这个数组中,并做为参数放入到InputEventDistributer::Distribute中进行事件的派发。

InputEventDistributer

\foundation\graphic\wms\services\ims\input_event_distributer.cpp

  1. void InputEventDistributer::Distribute(const RawEvent* events, int32_t size
  2.     for (int32_t i = 0; i < size; i++) { 
  3.         for (auto listener : rawEventListeners_) { 
  4.             if (listener != nullptr) { 
  5.                 listener->OnRawEvent(events[i]); 
  6.             } 
  7.         } 
  8.     } 

这个函数比较简单,主要就是遍历所有的InputEventClientProxy, 并且调用各自的onRawEvent进行实际的派发工作。

InputEventClientProxy

\foundation\graphic\wms\services\ims\input_event_client_proxy.cpp

  1. void InputEventClientProxy::OnRawEvent(const RawEvent& event) 
  2.     IpcIo io; 
  3.     uint8_t tmpData[IMS_DEFAULT_IPC_SIZE]; 
  4.     IpcIoInit(&io, tmpData, IMS_DEFAULT_IPC_SIZE, 1); 
  5.     IpcIoPushFlatObj(&io, static_cast<const void*>(&event), sizeof(RawEvent)); 
  6.     pthread_mutex_lock(&lock_); 
  7.     std::map<pid_t, ClientInfo>::iterator it; 
  8.     for (it = clientInfoMap_.begin(); it != clientInfoMap_.end(); it++) { 
  9.         if (it->second.alwaysInvoke || (event.state != lastState_)) { 
  10.             SendRequest(nullptr, it->second.svc, 0, &io, nullptr, LITEIPC_FLAG_ONEWAY, nullptr); 
  11.         } 
  12.     } 
  13.     lastState_ = event.state; 
  14.     pthread_mutex_unlock(&lock_); 

这个函数主要就是通过ipc的交互方式把输入事件传给应用端。

到此整个多模输入系统的事件派发流程就结束了。

多模输入系统接口说明

模块

  1. /foundation/multimodalinput/input 
  2. ├── common                       # 公共代码 
  3. ├── interfaces                   # 对外接口存放目录 
  4. │   └── native                   # 对外native层接口存放目录 
  5. │       └── innerkits            # 对系统内部子系统提供native层接口存放目录 
  6. ├── service                      # 服务框架代码 
  7. ├── sa_profile                   # 服务启动配置文件 
  8. ├── uinput                       # 输入事件注入模块 

通过每个目录下的.gn文件可以看到每个目录下的模块都对应动态库

\interfaces\native\innerkits\event下的文件编出来的是mmi_event.so

\interfaces\native\innerkits\napi 下的文件编出来的是injecteventhandler.so

\interfaces\native\innerkits\proxy 下的文件编出来的是libmultimodalinput_proxy.so

\service 下的文件编出来的是libmultimodalinput_service.so

\uinput 下的文件编出来的是mmi_uinject.so

接口

多模输入目前提供的接口为事件注入接口,该接口目前仅对系统应用开放。

JS接口

InJectEventHandler是处理注入事件类。

\applications\standard\systemui\navigationBar\src\main\js\default\pages\backKey\backKey.js

  1. export default { 
  2.     /** 
  3.      * User start touching the back button 
  4.      */ 
  5.     backTouchStart() { 
  6.         mLog.showInfo(TAG, `back touch start`); 
  7.         res = input.injectEventSync({ 
  8.             isPressed: true
  9.             keyCode: 2, 
  10.             keyDownDuration: 1 
  11.         }); 
  12.         mLog.showInfo(TAG, `injectEventHandler injectEventSync down res: ${res}`); 
  13.     }, 
  14.     /** 
  15.      * User stop touching the back button 
  16.      * Trigger "Back" event 
  17.      */ 
  18.     backTouchEnd() { 
  19.         mLog.showInfo(TAG, `back touch end and injectEventHandler injectEventSync`); 
  20.         res = input.injectEventSync({ 
  21.             isPressed: false
  22.             keyCode: 2, 
  23.             keyDownDuration: 1 
  24.         }); 
  25.         mLog.showInfo(TAG, `injectEventHandler injectEventSync up res: ${res}`); 
  26.     } 

可以从openharmony systemui的navigationbar的源码中看到, 当点击navigationbar的back键的时候,就会调用js的接口函数injectEventSync,并传入三个参数,其中

isPress: 按键的状态,true表示down, false表示up

keyCode:键值码,2表示back事件

keyDownDuration:按键按下到抬起之间的时长,单位ms,1表示1ms

C++接口

系统内部接口

在\interfaces\native\innerkits\events\include下的头文件都定义了各自对内部系统调用的口。

KeyEvent的主要接口

KeyBoardEvent的主要接口

ManipulationEvent的主要接口

MmiPoint的主要接口

MouseEvent的主要接口

MultimodalEvent的主要接口

StylusEvent的主要接口

TouchEvent的主要接口

InjectEvent的实现逻辑

\foundation\multimodalinput\input\interfaces\native\innerkits\napi\src\key_event_handler.cpp

  1. static napi_value InjectEventSync(napi_env env, napi_callback_info info) 
  2.     size_t argc = 2; 
  3.     napi_value args[2] = { 0 }; 
  4.     napi_value thisArg = nullptr; 
  5.     void* data = nullptr; 
  6.     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, &data)); 
  7.     napi_value eventObject = args[0]; 
  8.     int32_t ret = IsMatchType(eventObject, napi_object, env); 
  9.     if (ret) { 
  10.         return GetNapiInt32_t(ret, env); 
  11.     } 
  12.     napi_value isPressed, keyCode, keyDownDuration; 
  13.     napi_get_named_property(env, eventObject, "isPressed", &isPressed); 
  14.     napi_get_named_property(env, eventObject, "keyDownDuration", &keyDownDuration); 
  15.     napi_get_named_property(env, eventObject, "keyCode", &keyCode); 
  16.     if (IsMatchType(isPressed, napi_boolean, env) || IsMatchType(keyCode, napi_number, env) 
  17.         || IsMatchType(keyDownDuration, napi_number, env)) { 
  18.         return GetNapiInt32_t(-1, env); 
  19.     } 
  20.     OHOS::KeyProperty keyProperty = { 
  21.         .isPressed = GetCppBool(isPressed, env), 
  22.         .keyCode = GetCppInt32_t(keyCode, env), 
  23.         .keyDownDuration = GetCppInt32_t(keyDownDuration, env), 
  24.     }; 
  25.     OHOS::MultimodalProperty multimodalProperty { 
  26.         .highLevelEvent = 1, 
  27.         .uuid = "11111"
  28.         .sourceType = 1, 
  29.         .occurredTime = 1, 
  30.         .deviceId = "11111"
  31.         .inputDeviceId = 1, 
  32.         .isHighLevelEvent = true
  33.     }; 
  34.     OHOS::sptr<OHOS::KeyEvent> event = new OHOS::KeyEvent(); 
  35.     if (!event) { 
  36.         return GetNapiInt32_t(-1, env); 
  37.     } 
  38.     event->Initialize(multimodalProperty, keyProperty); 
  39.     std::shared_ptr<OHOS::InjectManager> injectManager = OHOS::InjectManager::GetInstance(); 
  40.     bool isSucceed = injectManager->InjectEvent(event); 
  41.     if (!isSucceed) { 
  42.         return GetNapiInt32_t(-1, env); 
  43.     } 
  44.     return GetNapiInt32_t(0, env); 

在key_event_handler.cpp中实现了InjectEventSync这个接口,通过NAPI获得应用端的isPressed,KeyDownDuration,KeyCode这三个数值,并将这三个参数放入到KeyProperty这个结构体中。然后调用KeyEvent的Initialize,将KeyProperty封装到KeyEvent中,最后再调用InjectManager的InjectEvent。

\foundation\multimodalinput\input\interfaces\native\innerkits\proxy\src\inject_manager.cpp

  1. bool InjectManager::InjectEvent(const sptr<MultimodalEvent> event) 
  2.     std::lock_guard<std::mutex> guard(lock_); 
  3.     if (!multimodalInputService_) { 
  4.         return false
  5.     } 
  6.  
  7.     int32_t result = multimodalInputService_->InjectEvent(event); 
  8.     if (result == 0) { 
  9.         return true
  10.     } 
  11.  
  12.     MMI_LOGI("inject failed"); 
  13.     return false

foundation\multimodalinput\input\interfaces\native\innerkits\proxy\include\inject_manager.h

  1. sptr<IMultimodalInputService> multimodalInputService_{nullptr}; 

multimodalInputService_->InjectEvent其实是一个IPC进程间调用,这会调用到客户端的MultimodalInputServiceProxy的InjectEvent。

foundation\multimodalinput\input\interfaces\native\innerkits\proxy\src\multimodal_input_service_proxy.cpp

  1. int32_t MultimodalInputServiceProxy::InjectEvent(const sptr<MultimodalEvent> &event) 
  2.     MessageParcel data; 
  3.     MessageParcel reply; 
  4.     MessageOption option(MessageOption::TF_ASYNC); 
  5.     if (!data.WriteInterfaceToken(MultimodalInputServiceProxy::GetDescriptor())) { 
  6.         HiLog::Error(LABEL, "write descriptor fail"); 
  7.         return ERR_INVALID_VALUE; 
  8.     } 
  9.  
  10.     if (!data.WriteInt32(MultimodalEvent::KEYBOARD)) { 
  11.         HiLog::Error(LABEL, "write descriptor fail"); 
  12.         return ERR_INVALID_VALUE; 
  13.     } 
  14.  
  15.     if (!data.WriteParcelable(event)) { 
  16.         HiLog::Error(LABEL, "inject event fail, write event error"); 
  17.         return ERR_INVALID_VALUE; 
  18.     } 
  19.     int error = Remote()->SendRequest(INJECT_EVENT, data, reply, option); 
  20.     if (error != ERR_NONE) { 
  21.         HiLog::Error(LABEL, "inject event fail, error: %{public}d", error); 
  22.     } 
  23.     return error; 

在MultimodalInputServiceProxy::InjectEvent会通过SendRequest向服务端MultimodalInputServiceStub发送数据。

foundation\multimodalinput\input\service\src\multimodal_input_service_stub.cpp

  1. int MultimodalInputServiceStub::OnRemoteRequest( 
  2.     uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option
  3.     MMI_LOGD("OnReceived, cmd = %{public}u", code); 
  4.     if (!IsPermissionValid()) { 
  5.         MMI_LOGE("calling app not acquired multimodal permission"); 
  6.         return MMI_PERMISSION_ERR; 
  7.     } 
  8.  
  9.     std::u16string myDescripter = MultimodalInputServiceStub::GetDescriptor(); 
  10.     std::u16string remoteDescripter = data.ReadInterfaceToken(); 
  11.     if (myDescripter != remoteDescripter) { 
  12.         MMI_LOGE("descriptor checked fail"); 
  13.         return MMI_BAD_TYPE; 
  14.     } 
  15.  
  16.     switch (code) { 
  17.         case INJECT_EVENT: { 
  18.             int32_t type = data.ReadInt32(); 
  19.             if (type == MultimodalEvent::KEYBOARD) { 
  20.                 sptr<MultimodalEvent> event = data.ReadParcelable<KeyEvent>(); 
  21.                 return InjectEvent(event); 
  22.             } 
  23.             MMI_LOGE("recv bad type %{public}d", type); 
  24.             return MMI_BAD_TYPE; 
  25.         } 
  26.         default: { 
  27.             MMI_LOGE("default case, need check"); 
  28.             return IPCObjectStub::OnRemoteRequest(code, data, reply, option); 
  29.         } 
  30.     } 

通过sendRequest将数据发送之后,服务端的MultimodalInputServiceStub的OnRemoteRequest就会被调用,最终会调用MultimodaInputService的InjectEvent。

\foundation\multimodalinput\input\service\src\multimodal_input_service.cpp

  1. int32_t MultimodalInputService::InjectEvent(const sptr<MultimodalEvent> &event) 
  2.     KeyEvent *eventPtr = reinterpret_cast<KeyEvent*>(event.GetRefPtr()); 
  3.     int keycode = eventPtr->GetKeyCode(); 
  4.     int state = 0; 
  5.     if (eventPtr->IsKeyDown()) { 
  6.         state = 1; 
  7.     } else { 
  8.         state = 0; 
  9.     } 
  10.     MMIS::KeyboardInject &inject = OHOS::MMIS::KeyboardInject::GetInstance(); 
  11.     MMI_LOGD("InjectEvent keycode %{public}d, state %{public}d", keycode, state); 
  12.     inject.InjectKeyEvent(keycode, state); 
  13.     return 0; 

MultimodaInputService的InjectEvent实际上会调用KeyboardInject的InjectKeyEvent,从函数的实现来看,目前只使用了KeyboardInject,也就是说目前只支持键盘事件的注入。

\foundation\multimodalinput\input\uinput\keyboard_inject.cpp

  1. void KeyboardInject::InjectKeyEvent(uint16_t code, uint32_t value) const 
  2.     std::lock_guard<std::mutex> keyboardLock(mutex_); 
  3.     auto it = keyCodeMap_.find(code); 
  4.     if (it == keyCodeMap_.end()) { 
  5.         return
  6.     } 
  7.     InjectInputEvent injectInputEvent = {injectThread_->KEYBOARD_DEVICE_ID, EV_KEY, it->second, value}; 
  8.     injectThread_->WaitFunc(injectInputEvent); 
  9.     InjectInputEvent injectInputSync = {injectThread_->KEYBOARD_DEVICE_ID, EV_SYN, SYN_REPORT, 0}; 
  10.     injectThread_->WaitFunc(injectInputSync); 

在InjectKeyEvent中会通过InjectInputEvent的WaitFunc将注入事件继续向下注入。

\foundation\multimodalinput\input\uinput\inject_thread.cpp

  1. void InjectThread::InjectFunc() const 
  2.     std::unique_lock<std::mutex> uniqueLock(mutex_); 
  3.     while (true) { 
  4.         conditionVariable_.wait(uniqueLock); 
  5.         while (injectQueue_.size() > 0) { 
  6.             if (injectQueue_[0].deviceId == TOUCH_SCREEN_DEVICE_ID) { 
  7.                 g_pTouchScreen->EmitEvent(injectQueue_[0].type, injectQueue_[0].code, injectQueue_[0].value); 
  8.             } else if (injectQueue_[0].deviceId == KEYBOARD_DEVICE_ID) { 
  9.                 g_pKeyboard->EmitEvent(injectQueue_[0].type, injectQueue_[0].code, injectQueue_[0].value); 
  10.             } 
  11.             injectQueue_.erase(injectQueue_.begin()); 
  12.         } 
  13.     } 
  14.  
  15. void InjectThread::WaitFunc(InjectInputEvent injectInputEvent) const 
  16.     std::lock_guard<std::mutex> lockGuard(mutex_); 
  17.     injectQueue_.push_back(injectInputEvent); 
  18.     conditionVariable_.notify_one(); 

在WaitFunc中会将injectInputEvent放入到injectQueue这个队列中,这个队列是用来存放injectInputEvent的,并且通过notify_one来唤醒InjectThread,由于目前只支持键盘类型事件的注入,所有只会调用g_pKeyboard->EmitEven(),g_pKeyboard是VirtualKeyboard的对象,VirtualKeyboard又继承自VirtualDevice,因此最终会调用VirtualKeyboard的EmitEvent。

foundation\multimodalinput\input\uinput\virtual_device.cpp

  1. bool VirtualDevice::EmitEvent(uint16_t type, uint16_t code, uint32_t value) const 
  2.     struct input_event event {}; 
  3.     event.type = type; 
  4.     event.code = code; 
  5.     event.value = value; 
  6. #ifndef __MUSL__ 
  7.     gettimeofday(&event.timeNULL); 
  8. #endif 
  9.     if (write(fd_, &event, sizeof(event)) < static_cast<ssize_t>(sizeof(event))) { 
  10.         HiLog::Error(LABEL, "Event write failed %{public}s aborting", __func__); 
  11.         return false
  12.     } 
  13.     return true
  14.  
  15. bool VirtualDevice::SetUp() 
  16.     fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK); 

在该函数中会将这个注入事件写入到文件描述符为fd_的设备文件中,从SetUp的函数中可以看出实际是写入到/dev/uinput这个设备文件中。

到此多模输入系统接口的介绍以及InjectEvent整个注入事件的流程就结束了。

总结

通过本文的学习可以了解多模输入系统事件派发的流程,以及多模输入系统的接口和注入事件的流程,结合以上的源码分析会对多模输入子系统会有更深入的理解。

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

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

https://harmonyos.51cto.com

 

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

2023-04-06 09:14:11

多模输入子系统鸿蒙

2021-09-13 15:15:18

鸿蒙HarmonyOS应用

2023-06-28 15:00:02

开源鸿蒙输入系统架构

2022-01-06 16:17:58

鸿蒙HarmonyOS应用

2022-02-17 20:57:07

OpenHarmon操作系统鸿蒙

2021-12-17 16:42:09

鸿蒙HarmonyOS应用

2021-11-08 15:04:47

鸿蒙HarmonyOS应用

2021-09-18 14:40:37

鸿蒙HarmonyOS应用

2023-04-12 15:31:11

系统服务管理鸿蒙

2022-01-10 15:30:11

鸿蒙HarmonyOS应用

2022-05-10 11:17:27

电话子系统数据服务模块

2021-11-18 10:28:03

鸿蒙HarmonyOS应用

2022-05-24 15:46:51

Wi-FiSTA模式

2022-01-20 14:33:29

openharmonwayland协议鸿蒙

2022-01-13 10:11:59

鸿蒙HarmonyOS应用

2022-05-20 10:32:49

事件循环器事件队列鸿蒙

2022-06-07 10:33:29

Camera组件鸿蒙

2022-05-30 15:08:33

包管理子系统包安装模块

2010-08-04 13:23:29

Flex事件

2010-08-09 11:14:36

Flex事件处理
点赞
收藏

51CTO技术栈公众号