OpenHarmony 源碼解析之多模輸入子系統(tǒng)(事件派發(fā)流程)
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)
簡(jiǎn)介
多模輸入系統(tǒng)主要用于接收按鍵,觸摸等輸入事件,并且會(huì)對(duì)這些原始輸入事件進(jìn)行處理,之后再對(duì)這些事件進(jìn)行派發(fā)。同時(shí)多模輸入系統(tǒng)還提供了注入事件的接口,應(yīng)用可以通過(guò)調(diào)用這個(gè)接口產(chǎn)生輸入事件,然后將該輸入事件注入到輸入系統(tǒng)中進(jìn)行處理。

輸入系統(tǒng)框架

多模輸入系統(tǒng)主要是由InputManagerService, InputEventHub, InputEventDistributer來(lái)負(fù)責(zé)處理的。InputManagerService會(huì)啟動(dòng)InputEventHub,并且會(huì)通過(guò)創(chuàng)建子線程的方式來(lái)創(chuàng)建InputEventDistributer。當(dāng)?shù)讓觽鱽?lái)按鍵或觸摸事件的時(shí)候,InputEventHub就會(huì)進(jìn)行讀取,并且會(huì)對(duì)這些原始的輸入事件進(jìn)行處理,處理完后會(huì)交給InputEventDistributer進(jìn)行派發(fā)。InputEventDistributer又會(huì)通過(guò)InputEventClientProxy進(jìn)行IPC交互的方式發(fā)給應(yīng)用端。
多模輸入系統(tǒng)事件派發(fā)流程
事件派發(fā)流程圖

源碼分析
下面就對(duì)多模輸入系統(tǒng)事件派發(fā)流程的源碼進(jìn)行分析。
InputManagerService
\foundation\graphic\wms\services\wms\wms.cpp
- int main()
- {
- DEBUG_PERFORMANCE_REGISTER_SIG();
- OHOS::HiFbdevInit();
- OHOS::GfxEngines::GetInstance()->InitDriver();
- HOS_SystemInit();
- OHOS::InputManagerService::GetInstance()->Run();
- while (1) {
- DEBUG_PERFORMANCE_PRINT_RESULT();
- OHOS::LiteWM::GetInstance()->MainTaskHandler();
- usleep(WMS_MAIN_TASK_PERIOD_IN_US);
- }
- }
InputManagerService的啟動(dòng)是在WMS的main函數(shù)中通過(guò)InputManagerService::GetInstance()->Run()執(zhí)行的。
\foundation\graphic\wms\services\ims\input_manager_service.cpp
- void InputManagerService::Run()
- {
- hub_ = InputEventHub::GetInstance();
- hub_->RegisterReadCallback(ReadCallback);
- hub_->SetUp();
- distributerThreadCreated_ = pthread_create(&distributerThread_, nullptr, Distribute, nullptr);
- if (!distributerThreadCreated_) {
- pthread_detach(distributerThread_);
- }
- }
在InputManagerService::Run()中首先會(huì)創(chuàng)建InputEventHub的對(duì)象并通過(guò)RegisterReadCallback來(lái)注冊(cè)InputEventHub的回調(diào),然后通過(guò)SetUp來(lái)啟動(dòng)InputEventHub, InputEventHub主要是用于對(duì)底層原始輸入事件的讀取和處理,該函數(shù)的最后會(huì)創(chuàng)建distributerThread子線程,用于對(duì)輸入事件的派發(fā)。
InputEventHub
\foundation\graphic\wms\services\ims\input_event_hub.cpp
- void InputEventHub::SetUp()
- {
- int32_t ret = GetInputInterface(&inputInterface_);
- if (ret != INPUT_SUCCESS) {
- GRAPHIC_LOGE("get input driver interface failed!");
- return;
- }
- uint8_t num = ScanInputDevice();
- if (num == 0) {
- GRAPHIC_LOGE("There is no device!");
- return;
- }
- for (uint8_t i = 0; i < num; i++) {
- if (inputInterface_ == nullptr || inputInterface_->iInputManager == nullptr) {
- GRAPHIC_LOGE("input interface or input manager is nullptr, open device failed!");
- return;
- }
- ret = inputInterface_->iInputManager->OpenInputDevice(mountDevIndex_[i]);
- if (ret == INPUT_SUCCESS && inputInterface_->iInputReporter != nullptr) {
- callback_.EventPkgCallback = EventCallback;
- ret = inputInterface_->iInputReporter->RegisterReportCallback(mountDevIndex_[i], &callback_);
- if (ret != INPUT_SUCCESS) {
- GRAPHIC_LOGE("device dose not exist, can't register callback to it!");
- return;
- }
- openDev_ = openDev_ | (1 << i);
- }
- }
- }
在這個(gè)函數(shù)中InputEventHub主要的工作就是通過(guò)調(diào)用驅(qū)動(dòng)層的OpenInputDevice來(lái)打開輸入設(shè)備,并且會(huì)將EventCallback的回調(diào)函數(shù)通過(guò)驅(qū)動(dòng)層的RegisterReportCallback進(jìn)行注冊(cè)。當(dāng)?shù)讓佑惺录鬟f上來(lái),EventCallback就會(huì)被調(diào)用。OpenInputDevice和RegisterReportCallback具體實(shí)現(xiàn)分別是在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
- void InputEventHub::EventCallback(const EventPackage **pkgs, uint32_t count, uint32_t devIndex)
- {
- if (pkgs == nullptr || readCallback_ == nullptr || count == 0) {
- return;
- }
- RawEvent& data = InputEventHub::GetInstance()->data_;
- for (uint32_t i = 0; i < count; i++) {
- if (pkgs[i]->type == EV_REL) {
- data.type = InputDevType::INDEV_TYPE_MOUSE;
- if (pkgs[i]->code == REL_X)
- data.x += pkgs[i]->value;
- else if (pkgs[i]->code == REL_Y)
- data.y += pkgs[i]->value;
- } else if (pkgs[i]->type == EV_ABS) {
- data.type = InputDevType::INDEV_TYPE_TOUCH;
- if (pkgs[i]->code == ABS_MT_POSITION_X)
- data.x = pkgs[i]->value;
- else if (pkgs[i]->code == ABS_MT_POSITION_Y)
- data.y = pkgs[i]->value;
- } else if (pkgs[i]->type == EV_KEY) {
- if (pkgs[i]->code == BTN_MOUSE || pkgs[i]->code == BTN_TOUCH) {
- if (pkgs[i]->value == 0)
- data.state = 0;
- else if (pkgs[i]->value == 1)
- data.state = 1;
- }
- } else if (pkgs[i]->type == EV_SYN) {
- if (pkgs[i]->code == SYN_REPORT) {
- break;
- }
- }
- }
- readCallback_(&data);
- }
當(dāng)?shù)讓佑休斎胧录蟻?lái)的話,EventCallback就會(huì)被調(diào)用,在這個(gè)函數(shù)里會(huì)通過(guò)EventPackage->type來(lái)判斷輸入事件的類型,其中
EV_REL是相對(duì)坐標(biāo)的輸入事件,比如軌跡球,鼠標(biāo)事件
EV_ABS是絕對(duì)坐標(biāo)的輸入事件,比如觸屏觸摸事件
EV_KEY是按鍵輸入事件,比如設(shè)備上的物理按鍵的點(diǎn)擊事件
EV_SYN是Motion的一系列動(dòng)作結(jié)束標(biāo)志位
如果是鼠標(biāo)事件,會(huì)將相對(duì)坐標(biāo)值放入到data.x和data.y中,如果是觸屏觸摸事件,會(huì)將在觸屏上觸摸的坐標(biāo)位置放入到data.x和data.y中,如果是按鍵事件會(huì)將按鍵的點(diǎn)擊狀態(tài)放入到data.state中。
處理完輸入事件后,會(huì)將數(shù)據(jù)放入到data中,并通過(guò)readCallback傳給InputManagerService進(jìn)行處理,之后就會(huì)調(diào)用InputManagerService::ReadCallback。
\foundation\graphic\wms\services\ims\input_manager_service.cpp
- void InputManagerService::ReadCallback(const RawEvent* event)
- {
- if (event == nullptr) {
- return;
- }
- pthread_mutex_lock(&lock_);
- while (eventQueue_.size() == MAX_EVENT_SIZE) {
- pthread_cond_wait(&nonFull_, &lock_);
- }
- // push events into queue
- eventQueue_.push(event[0]);
- pthread_mutex_unlock(&lock_);
- pthread_cond_signal(&nonEmpty_);
- }
- void* InputManagerService::Distribute(void* args)
- {
- GRAPHIC_LOGI("InputManagerService::Distribute Ready to read distribute!");
- while (true) {
- pthread_mutex_lock(&lock_);
- while (eventQueue_.size() == 0) {
- pthread_cond_wait(&nonEmpty_, &lock_);
- }
- // pop events from queue
- RawEvent events[MAX_INPUT_DEVICE_NUM];
- int32_t len = (eventQueue_.size() > MAX_EVENT_SIZE) ? MAX_EVENT_SIZE : eventQueue_.size();
- for (int32_t i = 0; i < len; i++) {
- events[i] = eventQueue_.front();
- eventQueue_.pop();
- }
- distributer_.Distribute(events, len);
- pthread_mutex_unlock(&lock_);
- pthread_cond_signal(&nonFull_);
- }
- return nullptr;
- }
ReadCallback這個(gè)函數(shù)首先會(huì)判斷eventQueue這個(gè)事件隊(duì)列里事件數(shù)量是否達(dá)到最大數(shù)量,如果達(dá)到最大數(shù)量該線程就一直等待,否則就會(huì)把該事件放到eventQueue這個(gè)事件隊(duì)列里,并且同時(shí)也會(huì)發(fā)出nonEmpty的signal, 來(lái)讓Distribute中的線程停止等待。
Distribute函數(shù)中,當(dāng)eventQueue隊(duì)列里沒有事件的時(shí)候,就會(huì)一直等待,當(dāng)有事件來(lái)的時(shí)候就會(huì)停止線程等待,然后會(huì)遍歷整個(gè)eventQueue這個(gè)隊(duì)列,把每個(gè)事件獲取出來(lái)后放入到events這個(gè)數(shù)組中,并做為參數(shù)放入到InputEventDistributer::Distribute中進(jìn)行事件的派發(fā)。
InputEventDistributer
\foundation\graphic\wms\services\ims\input_event_distributer.cpp
- void InputEventDistributer::Distribute(const RawEvent* events, int32_t size)
- {
- for (int32_t i = 0; i < size; i++) {
- for (auto listener : rawEventListeners_) {
- if (listener != nullptr) {
- listener->OnRawEvent(events[i]);
- }
- }
- }
- }
這個(gè)函數(shù)比較簡(jiǎn)單,主要就是遍歷所有的InputEventClientProxy, 并且調(diào)用各自的onRawEvent進(jìn)行實(shí)際的派發(fā)工作。
InputEventClientProxy
\foundation\graphic\wms\services\ims\input_event_client_proxy.cpp
- void InputEventClientProxy::OnRawEvent(const RawEvent& event)
- {
- IpcIo io;
- uint8_t tmpData[IMS_DEFAULT_IPC_SIZE];
- IpcIoInit(&io, tmpData, IMS_DEFAULT_IPC_SIZE, 1);
- IpcIoPushFlatObj(&io, static_cast<const void*>(&event), sizeof(RawEvent));
- pthread_mutex_lock(&lock_);
- std::map<pid_t, ClientInfo>::iterator it;
- for (it = clientInfoMap_.begin(); it != clientInfoMap_.end(); it++) {
- if (it->second.alwaysInvoke || (event.state != lastState_)) {
- SendRequest(nullptr, it->second.svc, 0, &io, nullptr, LITEIPC_FLAG_ONEWAY, nullptr);
- }
- }
- lastState_ = event.state;
- pthread_mutex_unlock(&lock_);
- }
這個(gè)函數(shù)主要就是通過(guò)ipc的交互方式把輸入事件傳給應(yīng)用端。
到此整個(gè)多模輸入系統(tǒng)的事件派發(fā)流程就結(jié)束了。
多模輸入系統(tǒng)接口說(shuō)明
模塊
- /foundation/multimodalinput/input
- ├── common # 公共代碼
- ├── interfaces # 對(duì)外接口存放目錄
- │ └── native # 對(duì)外native層接口存放目錄
- │ └── innerkits # 對(duì)系統(tǒng)內(nèi)部子系統(tǒng)提供native層接口存放目錄
- ├── service # 服務(wù)框架代碼
- ├── sa_profile # 服務(wù)啟動(dòng)配置文件
- ├── uinput # 輸入事件注入模塊
通過(guò)每個(gè)目錄下的.gn文件可以看到每個(gè)目錄下的模塊都對(duì)應(yīng)動(dòng)態(tài)庫(kù)
\interfaces\native\innerkits\event下的文件編出來(lái)的是mmi_event.so
\interfaces\native\innerkits\napi 下的文件編出來(lái)的是injecteventhandler.so
\interfaces\native\innerkits\proxy 下的文件編出來(lái)的是libmultimodalinput_proxy.so
\service 下的文件編出來(lái)的是libmultimodalinput_service.so
\uinput 下的文件編出來(lái)的是mmi_uinject.so
接口
多模輸入目前提供的接口為事件注入接口,該接口目前僅對(duì)系統(tǒng)應(yīng)用開放。
JS接口
InJectEventHandler是處理注入事件類。
\applications\standard\systemui\navigationBar\src\main\js\default\pages\backKey\backKey.js
- export default {
- /**
- * User start touching the back button
- */
- backTouchStart() {
- mLog.showInfo(TAG, `back touch start`);
- res = input.injectEventSync({
- isPressed: true,
- keyCode: 2,
- keyDownDuration: 1
- });
- mLog.showInfo(TAG, `injectEventHandler injectEventSync down res: ${res}`);
- },
- /**
- * User stop touching the back button
- * Trigger "Back" event
- */
- backTouchEnd() {
- mLog.showInfo(TAG, `back touch end and injectEventHandler injectEventSync`);
- res = input.injectEventSync({
- isPressed: false,
- keyCode: 2,
- keyDownDuration: 1
- });
- mLog.showInfo(TAG, `injectEventHandler injectEventSync up res: ${res}`);
- }
- }
可以從openharmony systemui的navigationbar的源碼中看到, 當(dāng)點(diǎn)擊navigationbar的back鍵的時(shí)候,就會(huì)調(diào)用js的接口函數(shù)injectEventSync,并傳入三個(gè)參數(shù),其中
isPress: 按鍵的狀態(tài),true表示down, false表示up
keyCode:鍵值碼,2表示back事件
keyDownDuration:按鍵按下到抬起之間的時(shí)長(zhǎng),單位ms,1表示1ms
C++接口
系統(tǒng)內(nèi)部接口
在\interfaces\native\innerkits\events\include下的頭文件都定義了各自對(duì)內(nèi)部系統(tǒng)調(diào)用的口。
KeyEvent的主要接口
KeyBoardEvent的主要接口
ManipulationEvent的主要接口
MmiPoint的主要接口
MouseEvent的主要接口
MultimodalEvent的主要接口
StylusEvent的主要接口
TouchEvent的主要接口
InjectEvent的實(shí)現(xiàn)邏輯
\foundation\multimodalinput\input\interfaces\native\innerkits\napi\src\key_event_handler.cpp
- static napi_value InjectEventSync(napi_env env, napi_callback_info info)
- {
- size_t argc = 2;
- napi_value args[2] = { 0 };
- napi_value thisArg = nullptr;
- void* data = nullptr;
- NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, &thisArg, &data));
- napi_value eventObject = args[0];
- int32_t ret = IsMatchType(eventObject, napi_object, env);
- if (ret) {
- return GetNapiInt32_t(ret, env);
- }
- napi_value isPressed, keyCode, keyDownDuration;
- napi_get_named_property(env, eventObject, "isPressed", &isPressed);
- napi_get_named_property(env, eventObject, "keyDownDuration", &keyDownDuration);
- napi_get_named_property(env, eventObject, "keyCode", &keyCode);
- if (IsMatchType(isPressed, napi_boolean, env) || IsMatchType(keyCode, napi_number, env)
- || IsMatchType(keyDownDuration, napi_number, env)) {
- return GetNapiInt32_t(-1, env);
- }
- OHOS::KeyProperty keyProperty = {
- .isPressed = GetCppBool(isPressed, env),
- .keyCode = GetCppInt32_t(keyCode, env),
- .keyDownDuration = GetCppInt32_t(keyDownDuration, env),
- };
- OHOS::MultimodalProperty multimodalProperty {
- .highLevelEvent = 1,
- .uuid = "11111",
- .sourceType = 1,
- .occurredTime = 1,
- .deviceId = "11111",
- .inputDeviceId = 1,
- .isHighLevelEvent = true,
- };
- OHOS::sptr<OHOS::KeyEvent> event = new OHOS::KeyEvent();
- if (!event) {
- return GetNapiInt32_t(-1, env);
- }
- event->Initialize(multimodalProperty, keyProperty);
- std::shared_ptr<OHOS::InjectManager> injectManager = OHOS::InjectManager::GetInstance();
- bool isSucceed = injectManager->InjectEvent(event);
- if (!isSucceed) {
- return GetNapiInt32_t(-1, env);
- }
- return GetNapiInt32_t(0, env);
- }
在key_event_handler.cpp中實(shí)現(xiàn)了InjectEventSync這個(gè)接口,通過(guò)NAPI獲得應(yīng)用端的isPressed,KeyDownDuration,KeyCode這三個(gè)數(shù)值,并將這三個(gè)參數(shù)放入到KeyProperty這個(gè)結(jié)構(gòu)體中。然后調(diào)用KeyEvent的Initialize,將KeyProperty封裝到KeyEvent中,最后再調(diào)用InjectManager的InjectEvent。
\foundation\multimodalinput\input\interfaces\native\innerkits\proxy\src\inject_manager.cpp
- bool InjectManager::InjectEvent(const sptr<MultimodalEvent> event)
- {
- std::lock_guard<std::mutex> guard(lock_);
- if (!multimodalInputService_) {
- return false;
- }
- int32_t result = multimodalInputService_->InjectEvent(event);
- if (result == 0) {
- return true;
- }
- MMI_LOGI("inject failed");
- return false;
- }
foundation\multimodalinput\input\interfaces\native\innerkits\proxy\include\inject_manager.h
- sptr<IMultimodalInputService> multimodalInputService_{nullptr};
multimodalInputService_->InjectEvent其實(shí)是一個(gè)IPC進(jìn)程間調(diào)用,這會(huì)調(diào)用到客戶端的MultimodalInputServiceProxy的InjectEvent。
foundation\multimodalinput\input\interfaces\native\innerkits\proxy\src\multimodal_input_service_proxy.cpp
- int32_t MultimodalInputServiceProxy::InjectEvent(const sptr<MultimodalEvent> &event)
- {
- MessageParcel data;
- MessageParcel reply;
- MessageOption option(MessageOption::TF_ASYNC);
- if (!data.WriteInterfaceToken(MultimodalInputServiceProxy::GetDescriptor())) {
- HiLog::Error(LABEL, "write descriptor fail");
- return ERR_INVALID_VALUE;
- }
- if (!data.WriteInt32(MultimodalEvent::KEYBOARD)) {
- HiLog::Error(LABEL, "write descriptor fail");
- return ERR_INVALID_VALUE;
- }
- if (!data.WriteParcelable(event)) {
- HiLog::Error(LABEL, "inject event fail, write event error");
- return ERR_INVALID_VALUE;
- }
- int error = Remote()->SendRequest(INJECT_EVENT, data, reply, option);
- if (error != ERR_NONE) {
- HiLog::Error(LABEL, "inject event fail, error: %{public}d", error);
- }
- return error;
- }
在MultimodalInputServiceProxy::InjectEvent會(huì)通過(guò)SendRequest向服務(wù)端MultimodalInputServiceStub發(fā)送數(shù)據(jù)。
foundation\multimodalinput\input\service\src\multimodal_input_service_stub.cpp
- int MultimodalInputServiceStub::OnRemoteRequest(
- uint32_t code, MessageParcel &data, MessageParcel &reply, MessageOption &option)
- {
- MMI_LOGD("OnReceived, cmd = %{public}u", code);
- if (!IsPermissionValid()) {
- MMI_LOGE("calling app not acquired multimodal permission");
- return MMI_PERMISSION_ERR;
- }
- std::u16string myDescripter = MultimodalInputServiceStub::GetDescriptor();
- std::u16string remoteDescripter = data.ReadInterfaceToken();
- if (myDescripter != remoteDescripter) {
- MMI_LOGE("descriptor checked fail");
- return MMI_BAD_TYPE;
- }
- switch (code) {
- case INJECT_EVENT: {
- int32_t type = data.ReadInt32();
- if (type == MultimodalEvent::KEYBOARD) {
- sptr<MultimodalEvent> event = data.ReadParcelable<KeyEvent>();
- return InjectEvent(event);
- }
- MMI_LOGE("recv bad type %{public}d", type);
- return MMI_BAD_TYPE;
- }
- default: {
- MMI_LOGE("default case, need check");
- return IPCObjectStub::OnRemoteRequest(code, data, reply, option);
- }
- }
- }
通過(guò)sendRequest將數(shù)據(jù)發(fā)送之后,服務(wù)端的MultimodalInputServiceStub的OnRemoteRequest就會(huì)被調(diào)用,最終會(huì)調(diào)用MultimodaInputService的InjectEvent。
\foundation\multimodalinput\input\service\src\multimodal_input_service.cpp
- int32_t MultimodalInputService::InjectEvent(const sptr<MultimodalEvent> &event)
- {
- KeyEvent *eventPtr = reinterpret_cast<KeyEvent*>(event.GetRefPtr());
- int keycode = eventPtr->GetKeyCode();
- int state = 0;
- if (eventPtr->IsKeyDown()) {
- state = 1;
- } else {
- state = 0;
- }
- MMIS::KeyboardInject &inject = OHOS::MMIS::KeyboardInject::GetInstance();
- MMI_LOGD("InjectEvent keycode %{public}d, state %{public}d", keycode, state);
- inject.InjectKeyEvent(keycode, state);
- return 0;
- }
MultimodaInputService的InjectEvent實(shí)際上會(huì)調(diào)用KeyboardInject的InjectKeyEvent,從函數(shù)的實(shí)現(xiàn)來(lái)看,目前只使用了KeyboardInject,也就是說(shuō)目前只支持鍵盤事件的注入。
\foundation\multimodalinput\input\uinput\keyboard_inject.cpp
- void KeyboardInject::InjectKeyEvent(uint16_t code, uint32_t value) const
- {
- std::lock_guard<std::mutex> keyboardLock(mutex_);
- auto it = keyCodeMap_.find(code);
- if (it == keyCodeMap_.end()) {
- return;
- }
- InjectInputEvent injectInputEvent = {injectThread_->KEYBOARD_DEVICE_ID, EV_KEY, it->second, value};
- injectThread_->WaitFunc(injectInputEvent);
- InjectInputEvent injectInputSync = {injectThread_->KEYBOARD_DEVICE_ID, EV_SYN, SYN_REPORT, 0};
- injectThread_->WaitFunc(injectInputSync);
- }
在InjectKeyEvent中會(huì)通過(guò)InjectInputEvent的WaitFunc將注入事件繼續(xù)向下注入。
\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();
- }
在WaitFunc中會(huì)將injectInputEvent放入到injectQueue這個(gè)隊(duì)列中,這個(gè)隊(duì)列是用來(lái)存放injectInputEvent的,并且通過(guò)notify_one來(lái)喚醒InjectThread,由于目前只支持鍵盤類型事件的注入,所有只會(huì)調(diào)用g_pKeyboard->EmitEven(),g_pKeyboard是VirtualKeyboard的對(duì)象,VirtualKeyboard又繼承自VirtualDevice,因此最終會(huì)調(diào)用VirtualKeyboard的EmitEvent。
foundation\multimodalinput\input\uinput\virtual_device.cpp
- 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;
- }
- bool VirtualDevice::SetUp()
- {
- fd_ = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
在該函數(shù)中會(huì)將這個(gè)注入事件寫入到文件描述符為fd_的設(shè)備文件中,從SetUp的函數(shù)中可以看出實(shí)際是寫入到/dev/uinput這個(gè)設(shè)備文件中。
到此多模輸入系統(tǒng)接口的介紹以及InjectEvent整個(gè)注入事件的流程就結(jié)束了。
總結(jié)
通過(guò)本文的學(xué)習(xí)可以了解多模輸入系統(tǒng)事件派發(fā)的流程,以及多模輸入系統(tǒng)的接口和注入事件的流程,結(jié)合以上的源碼分析會(huì)對(duì)多模輸入子系統(tǒng)會(huì)有更深入的理解。
想了解更多內(nèi)容,請(qǐng)?jiān)L問(wèn):
51CTO和華為官方合作共建的鴻蒙技術(shù)社區(qū)











































