• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include "multimodal_input_plugin_manager.h"
17 
18 #include "mmi_log.h"
19 #include <memory>
20 
21 #undef MMI_LOG_DOMAIN
22 #define MMI_LOG_DOMAIN MMI_LOG_SERVER
23 #undef MMI_LOG_TAG
24 #define MMI_LOG_TAG "MultiModalInputPluginManager"
25 
26 namespace OHOS {
27 namespace MMI {
28 std::shared_ptr<InputPluginManager> InputPluginManager::instance_;
29 std::once_flag InputPluginManager::init_flag_;
30 
31 const char *FILE_EXTENSION = ".so";
32 const char *FOLDER_PATH = "/system/lib64/multimodalinput/autorun";
33 const int32_t TIMEOUT_US = 300;
34 const int32_t MAX_TIMER = 3;
35 
~InputPluginManager()36 InputPluginManager::~InputPluginManager()
37 {
38     plugins_.clear();
39     if (instance_ != nullptr) {
40         instance_ = nullptr;
41     }
42     MMI_HILOGI("~InputPluginManager");
43 }
44 
GetInstance(const std::string & directory)45 std::shared_ptr<InputPluginManager> InputPluginManager::GetInstance(const std::string &directory)
46 {
47     std::call_once(init_flag_, [&directory] {
48         if (instance_ == nullptr) {
49             MMI_HILOGI("New InputPluginManager");
50             std::string dir = directory.empty() ? FOLDER_PATH : directory;
51             instance_ = std::make_shared<InputPluginManager>(dir);
52         }
53     });
54     return instance_;
55 }
56 
Init()57 int32_t InputPluginManager::Init()
58 {
59     CALL_DEBUG_ENTER;
60     DIR *dir = opendir(directory_.c_str());
61     if (!dir) {
62         MMI_HILOGE("Failed to open error:%{private}s", strerror(errno));
63         return RET_OK;
64     }
65     struct dirent *entry;
66     while ((entry = readdir(dir)) != nullptr) {
67         if (entry->d_type == DT_REG && std::string(entry->d_name) != "." && std::string(entry->d_name) != "..") {
68             std::string path = directory_ + "/" + entry->d_name;
69             if (path.length() >= strlen(FILE_EXTENSION) &&
70                 path.substr(path.size() - strlen(FILE_EXTENSION)) == FILE_EXTENSION) {
71                 LoadPlugin(path);
72             }
73         }
74     }
75     closedir(dir);
76     PrintPlugins();
77     return RET_OK;
78 }
79 
LoadPlugin(const std::string & path)80 bool InputPluginManager::LoadPlugin(const std::string &path)
81 {
82     CALL_DEBUG_ENTER;
83     void *handle = dlopen(path.c_str(), RTLD_LAZY);
84     if (!handle) {
85         MMI_HILOGE("Failed to load directory: %{private}s", dlerror());
86         return false;
87     }
88 
89     InitPlugin func = reinterpret_cast<InitPlugin>(dlsym(handle, "InitPlugin"));
90     if (!func) {
91         MMI_HILOGE("Failed to find symbol InitPlugin in: %{private}s", dlerror());
92         dlclose(handle);
93         return false;
94     }
95 
96     std::shared_ptr<InputPlugin> cPin = std::make_shared<InputPlugin>();
97     if (!cPin) {
98         dlclose(handle);
99         return false;
100     }
101 
102     cPin->unintPlugin_ = reinterpret_cast<UnintPlugin>(dlsym(handle, "UnintPlugin"));
103     if (!cPin->unintPlugin_) {
104         MMI_HILOGE("Failed to find symbol UnintPlugin in: %{private}s", dlerror());
105         dlclose(handle);
106         return false;
107     }
108     std::shared_ptr<IInputPlugin> iPin;
109     int32_t ret = func(cPin, iPin);
110     if (ret != 0 || !iPin) {
111         MMI_HILOGE("Failed to InitPlugin plugin.");
112         dlclose(handle);
113         return false;
114     }
115     ret = cPin->Init(iPin);
116     if (ret != 0) {
117         MMI_HILOGE("Failed to Init plugin.");
118         dlclose(handle);
119         return false;
120     }
121     cPin->handle_ = handle;
122     InputPluginStage stage = iPin->GetStage();
123 
124     auto result = plugins_.insert({stage, {cPin}});
125     if (!result.second) {
126         auto it = std::lower_bound(result.first->second.begin(), result.first->second.end(), cPin,
127             [](const std::shared_ptr<InputPlugin> &a, const std::shared_ptr<InputPlugin> &b) {
128                 return a->prio_ < b->prio_;
129             });
130         result.first->second.insert(it, cPin);
131     }
132     return true;
133 }
134 
PrintPlugins()135 void InputPluginManager::PrintPlugins()
136 {
137     for (const auto &stagePlugins : plugins_) {
138         MMI_HILOGI("InputPluginManager InputPluginStage : %{public}d", stagePlugins.first);
139         for (const auto &plugin : stagePlugins.second) {
140             MMI_HILOGI("InputPluginManager : name:%{public}s prio_:%{public}d",
141                 plugin->name_.c_str(), plugin->prio_);
142         }
143     }
144 }
145 
PluginAssignmentCallBack(std::function<void (libinput_event *,int64_t)> callback,InputPluginStage stage)146 void InputPluginManager::PluginAssignmentCallBack(
147     std::function<void(libinput_event *, int64_t)> callback, InputPluginStage stage)
148 {
149     CALL_DEBUG_ENTER;
150     auto it = plugins_.find(stage);
151     if (it == plugins_.end()) {
152         MMI_HILOGI("plugins_ not stage:%{public}d.", stage);
153         return;
154     }
155     for (auto &plugin : it->second) {
156         plugin->callback_ = callback;
157     }
158 }
159 
PluginAssignmentCallBack(std::function<void (std::shared_ptr<KeyEvent>)> callback,InputPluginStage stage)160 void InputPluginManager::PluginAssignmentCallBack(
161     std::function<void(std::shared_ptr<KeyEvent>)> callback, InputPluginStage stage)
162 {
163     CALL_DEBUG_ENTER;
164     auto it = plugins_.find(stage);
165     if (it == plugins_.end()) {
166         MMI_HILOGI("plugins_ not stage:%{public}d.", stage);
167         return;
168     }
169     for (auto &plugin : it->second) {
170         if (plugin != nullptr) {
171             plugin->keyEventCallback_ = callback;
172         }
173     }
174 }
175 
HandleEvent(libinput_event * event,int64_t frameTime,InputPluginStage stage)176 int32_t InputPluginManager::HandleEvent(libinput_event *event, int64_t frameTime, InputPluginStage stage)
177 {
178     return DoHandleEvent(event, frameTime, nullptr, stage);
179 }
180 
DoHandleEvent(libinput_event * event,int64_t frameTime,InputPlugin * iplugin,InputPluginStage stage)181 int32_t InputPluginManager::DoHandleEvent(
182     libinput_event *event, int64_t frameTime, InputPlugin *iplugin, InputPluginStage stage)
183 {
184     if (event == nullptr) {
185         return RET_NOTDO;
186     }
187     auto it = plugins_.find(stage);
188     if (it == plugins_.end()) {
189         return RET_NOTDO;
190     }
191     CALL_DEBUG_ENTER;
192     auto &plugins = it->second;
193     auto start_plugin = plugins.begin();
194     if (iplugin != nullptr) {
195         auto cur_plugin = std::find_if(plugins.begin(), plugins.end(),
196             [iplugin](const std::shared_ptr<InputPlugin> &plugin) { return plugin.get() == iplugin; });
197         if (cur_plugin == plugins.end()) {
198             return RET_NOTDO;
199         }
200         start_plugin = std::next(cur_plugin);
201     }
202     int64_t beginTime = 0;
203     PluginResult result;
204     int64_t endTime = 0;
205     int64_t lostTime = 0;
206     for (auto pluginIt = start_plugin; pluginIt != plugins.end(); ++pluginIt) {
207         if ((*pluginIt) == nullptr) {
208             continue;
209         }
210         beginTime = GetSysClockTime();
211         result = (*pluginIt)->HandleEvent(event, frameTime);
212         endTime = GetSysClockTime();
213         lostTime = endTime - beginTime;
214         if (lostTime >= TIMEOUT_US) {
215             MMI_HILOGE("pluginIt timeout name:%{public}s ,endTime:%{public}" PRId64 ",lostTime:%{public}" PRId64,
216                 (*pluginIt)->name_.c_str(), endTime, lostTime);
217         }
218         if (result == PluginResult::UseNeedReissue) {
219             if (IntermediateEndEvent(event)) {
220                 MMI_HILOGE("pluginIt is intermediate or end event");
221                 continue;
222             }
223             return RET_DO;
224         } else if (result == PluginResult::UseNoNeedReissue) {
225             return RET_DO;
226         } else if (result == PluginResult::Error) {
227             MMI_HILOGE("pluginIt err name:%{public}s", (*pluginIt)->name_.c_str());
228         }
229     }
230     return RET_NOTDO;
231 }
232 
HandleEvent(std::shared_ptr<KeyEvent> keyEvent,InputPluginStage stage)233 int32_t InputPluginManager::HandleEvent(std::shared_ptr<KeyEvent> keyEvent, InputPluginStage stage)
234 {
235     return DoHandleEvent(keyEvent, nullptr, stage);
236 }
237 
DoHandleEvent(std::shared_ptr<KeyEvent> keyEvent,InputPlugin * iplugin,InputPluginStage stage)238 int32_t InputPluginManager::DoHandleEvent(
239     std::shared_ptr<KeyEvent> keyEvent, InputPlugin *iplugin, InputPluginStage stage)
240 {
241     if (keyEvent == nullptr) {
242         return RET_NOTDO;
243     }
244     auto it = plugins_.find(stage);
245     if (it == plugins_.end()) {
246         return RET_NOTDO;
247     }
248     CALL_DEBUG_ENTER;
249     auto &plugins = it->second;
250     auto start_plugin = plugins.begin();
251     if (iplugin != nullptr) {
252         auto cur_plugin = std::find_if(plugins.begin(), plugins.end(),
253             [iplugin](const std::shared_ptr<InputPlugin> &plugin) { return plugin.get() == iplugin; });
254         if (cur_plugin == plugins.end()) {
255             return RET_NOTDO;
256         }
257         start_plugin = std::next(cur_plugin);
258     }
259     int64_t beginTime = 0;
260     PluginResult result;
261     int64_t endTime = 0;
262     int64_t lostTime = 0;
263     for (auto pluginIt = start_plugin; pluginIt != plugins.end(); ++pluginIt) {
264         if ((*pluginIt) == nullptr) {
265             continue;
266         }
267         beginTime = GetSysClockTime();
268         result = (*pluginIt)->HandleEvent(keyEvent, stage);
269         endTime = GetSysClockTime();
270         lostTime = endTime - beginTime;
271         if (lostTime >= TIMEOUT_US) {
272             MMI_HILOGE("pluginIt timeout name:%{public}s ,endTime:%{public}" PRId64 ",lostTime:%{public}" PRId64,
273                 (*pluginIt)->name_.c_str(), endTime, lostTime);
274         }
275         if (result == PluginResult::UseNeedReissue) {
276             return RET_DO;
277         } else if (result == PluginResult::UseNoNeedReissue) {
278             return RET_DO;
279         } else if (result == PluginResult::Error) {
280             MMI_HILOGE("pluginIt err name:%{public}s", (*pluginIt)->name_.c_str());
281         }
282     }
283     return RET_NOTDO;
284 }
285 
286 // LIBINPUT_EVENT_TABLET_TOOL_BUTTON、LIBINPUT_EVENT_TABLET_PAD_BUTTON、LIBINPUT_EVENT_TABLET_PAD_KEY
287 // These few existence termination events are currently not used and will be supplemented after use
IntermediateEndEvent(libinput_event * event)288 bool InputPluginManager::IntermediateEndEvent(libinput_event *event)
289 {
290     const libinput_event_type type = libinput_event_get_type(event);
291     switch (type) {
292         case LIBINPUT_EVENT_POINTER_MOTION:
293         case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
294         case LIBINPUT_EVENT_POINTER_AXIS:
295         case LIBINPUT_EVENT_POINTER_SCROLL_FINGER:
296         case LIBINPUT_EVENT_POINTER_SCROLL_CONTINUOUS:
297         case LIBINPUT_EVENT_POINTER_MOTION_TOUCHPAD:
298         case LIBINPUT_EVENT_POINTER_SCROLL_FINGER_END:
299         case LIBINPUT_EVENT_JOYSTICK_AXIS:
300         case LIBINPUT_EVENT_TOUCH_UP:
301         case LIBINPUT_EVENT_TOUCH_MOTION:
302         case LIBINPUT_EVENT_TOUCH_CANCEL:
303         case LIBINPUT_EVENT_TOUCHPAD_UP:
304         case LIBINPUT_EVENT_TOUCHPAD_MOTION:
305         case LIBINPUT_EVENT_TABLET_TOOL_AXIS:
306         case LIBINPUT_EVENT_TABLET_PAD_RING:
307         case LIBINPUT_EVENT_TABLET_PAD_STRIP:
308         case LIBINPUT_EVENT_GESTURE_SWIPE_UPDATE:
309         case LIBINPUT_EVENT_GESTURE_SWIPE_END:
310         case LIBINPUT_EVENT_GESTURE_PINCH_UPDATE:
311         case LIBINPUT_EVENT_GESTURE_PINCH_END:
312         case LIBINPUT_EVENT_GESTURE_HOLD_END:
313             return true;
314         case LIBINPUT_EVENT_KEYBOARD_KEY: {
315             struct libinput_event_keyboard *keyboardEvent = libinput_event_get_keyboard_event(event);
316             CHKPF(keyboardEvent);
317             return libinput_event_keyboard_get_key_state(keyboardEvent) == LIBINPUT_KEY_STATE_RELEASED;
318         }
319         case LIBINPUT_EVENT_POINTER_BUTTON:
320         case LIBINPUT_EVENT_POINTER_TAP:
321         case LIBINPUT_EVENT_POINTER_BUTTON_TOUCHPAD: {
322             auto touchpadButtonEvent = libinput_event_get_pointer_event(event);
323             CHKPF(touchpadButtonEvent);
324             return libinput_event_pointer_get_button_state(touchpadButtonEvent) == LIBINPUT_BUTTON_STATE_RELEASED;
325         }
326         case LIBINPUT_EVENT_JOYSTICK_BUTTON: {
327             auto rawBtnEvent = libinput_event_get_joystick_button_event(event);
328             CHKPF(rawBtnEvent);
329             return libinput_event_joystick_button_get_key_state(rawBtnEvent) == LIBINPUT_BUTTON_STATE_RELEASED;
330         }
331         case LIBINPUT_EVENT_TABLET_TOOL_PROXIMITY: {
332             auto tabletEvent = libinput_event_get_tablet_tool_event(event);
333             CHKPF(tabletEvent);
334             return libinput_event_tablet_tool_get_proximity_state(tabletEvent) ==
335                    LIBINPUT_TABLET_TOOL_PROXIMITY_STATE_OUT;
336         }
337         case LIBINPUT_EVENT_TABLET_TOOL_TIP: {
338             auto tabletEvent = libinput_event_get_tablet_tool_event(event);
339             CHKPF(tabletEvent);
340             return libinput_event_tablet_tool_get_tip_state(tabletEvent) == LIBINPUT_TABLET_TOOL_TIP_UP;
341         }
342         default:
343             break;
344     }
345     return false;
346 }
347 
Init(std::shared_ptr<IInputPlugin> pin)348 int32_t InputPlugin::Init(std::shared_ptr<IInputPlugin> pin)
349 {
350     name_ = pin->GetName();
351     prio_ = pin->GetPriority();
352     stage_ = pin->GetStage();
353     plugin_ = pin;
354     return RET_OK;
355 }
356 
UnInit()357 void InputPlugin::UnInit()
358 {
359     CHKPV(plugin_);
360     MMI_HILOGI("InputPlugin UnInit Start name:%{public}s.", name_.c_str());
361     if (unintPlugin_) {
362         unintPlugin_(plugin_);
363     }
364 }
365 
DispatchEvent(libinput_event * event,int64_t frameTime)366 void InputPlugin::DispatchEvent(libinput_event *event, int64_t frameTime)
367 {
368     int32_t result = InputPluginManager::GetInstance()->DoHandleEvent(event, frameTime, this, stage_);
369     if (result == RET_NOTDO) {
370         CHKPV(callback_);
371         callback_(event, frameTime);
372     }
373 }
374 
DispatchEvent(std::shared_ptr<KeyEvent> keyEvent,InputDispatchStage stage)375 void InputPlugin::DispatchEvent(std::shared_ptr<KeyEvent> keyEvent, InputDispatchStage stage)
376 {
377     int32_t result = InputPluginManager::GetInstance()->DoHandleEvent(keyEvent, this, stage_);
378     if (result == RET_NOTDO) {
379         CHKPV(keyEventCallback_);
380         keyEventCallback_(keyEvent);
381     }
382 }
383 
HandleEvent(libinput_event * event,int64_t frameTime)384 PluginResult InputPlugin::HandleEvent(libinput_event *event, int64_t frameTime)
385 {
386     CHKPR(plugin_, PluginResult::NotUse);
387     return plugin_->HandleEvent(event, frameTime);
388 }
389 
HandleEvent(std::shared_ptr<KeyEvent> keyEvent,InputPluginStage stage)390 PluginResult InputPlugin::HandleEvent(std::shared_ptr<KeyEvent> keyEvent, InputPluginStage stage)
391 {
392     CHKPR(plugin_, PluginResult::NotUse);
393     return plugin_->HandleEvent(keyEvent, stage);
394 }
395 
AddTimer(std::function<void ()> func,int32_t intervalMs,int32_t repeatCount)396 int32_t InputPlugin::AddTimer(std::function<void()> func, int32_t intervalMs, int32_t repeatCount)
397 {
398     if (timerCnt_ >= MAX_TIMER) {
399         return RET_ERR;
400     }
401     int32_t timerId = TimerMgr->AddTimerInternal(intervalMs, repeatCount, func, name_);
402     if (timerId != -1) {
403         timerCnt_++;
404     }
405     return timerId;
406 }
407 
RemoveTimer(int32_t id)408 int32_t InputPlugin::RemoveTimer(int32_t id)
409 {
410     int32_t result = TimerMgr->RemoveTimer(id, name_);
411     if (timerCnt_ > 0) {
412         timerCnt_--;
413     }
414     return result;
415 }
416 
~InputPlugin()417 InputPlugin::~InputPlugin()
418 {
419     if (handle_) {
420         dlclose(handle_);
421         handle_ = nullptr;
422     }
423     MMI_HILOGI("~InputPlugin");
424 }
425 } // namespace MMI
426 } // namespace OHOS
427