• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2021 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 "input_method_controller.h"
17 
18 #include "global.h"
19 #include "input_client_stub.h"
20 #include "input_data_channel_stub.h"
21 #include "input_method_agent_proxy.h"
22 #include "input_method_property.h"
23 #include "input_method_status.h"
24 #include "input_method_system_ability_proxy.h"
25 #include "inputmethod_sysevent.h"
26 #include "inputmethod_trace.h"
27 #include "iservice_registry.h"
28 #include "string_ex.h"
29 #include "system_ability_definition.h"
30 #include "utils.h"
31 
32 namespace OHOS {
33 namespace MiscServices {
34 using namespace MessageID;
35     sptr<InputMethodController> InputMethodController::instance_;
36     std::mutex InputMethodController::instanceLock_;
37     constexpr int32_t WAIT_TIME = 100;
38     constexpr int32_t KEYBOARD_SHOW = 2;
InputMethodController()39     InputMethodController::InputMethodController() : stop_(false)
40     {
41         IMSA_HILOGI("InputMethodController structure");
42         Initialize();
43     }
44 
~InputMethodController()45     InputMethodController::~InputMethodController()
46     {
47         QuitWorkThread();
48         delete msgHandler;
49         msgHandler = nullptr;
50     }
51 
GetInstance()52     sptr<InputMethodController> InputMethodController::GetInstance()
53     {
54         if (!instance_) {
55             std::lock_guard<std::mutex> autoLock(instanceLock_);
56             if (!instance_) {
57                 IMSA_HILOGI("InputMethodController::GetInstance instance_ is nullptr");
58                 instance_ = new InputMethodController();
59             }
60         }
61         return instance_;
62     }
63 
setImeListener(std::shared_ptr<InputMethodSettingListener> imeListener)64     void InputMethodController::setImeListener(std::shared_ptr<InputMethodSettingListener> imeListener)
65     {
66         IMSA_HILOGI("InputMethodController::setImeListener");
67         if (imeListener_ == nullptr) {
68             imeListener_ = imeListener;
69         }
70     }
71 
Initialize()72     bool InputMethodController::Initialize()
73     {
74         msgHandler = new MessageHandler();
75 
76         InputClientStub *client = new (std::nothrow) InputClientStub();
77         if (client == nullptr) {
78             IMSA_HILOGE("InputMethodController::Initialize client is nullptr");
79             return false;
80         }
81         client->SetHandler(msgHandler);
82         mClient = client;
83 
84         InputDataChannelStub *channel = new (std::nothrow) InputDataChannelStub();
85         if (channel == nullptr) {
86             IMSA_HILOGE("InputMethodController::Initialize channel is nullptr");
87             return false;
88         }
89         channel->SetHandler(msgHandler);
90         mInputDataChannel = channel;
91 
92         workThreadHandler = std::thread([this] { WorkThread(); });
93         mAttribute.inputPattern = InputAttribute::PATTERN_TEXT;
94         {
95             std::lock_guard<std::mutex> lock(textListenerLock_);
96             textListener = nullptr;
97         }
98         IMSA_HILOGI("InputMethodController::Initialize textListener is nullptr");
99         PrepareInput(0, mClient, mInputDataChannel, mAttribute);
100         return true;
101     }
102 
GetSystemAbilityProxy()103     sptr<IInputMethodSystemAbility> InputMethodController::GetSystemAbilityProxy()
104     {
105         std::lock_guard<std::mutex> lock(abilityLock_);
106         if (abilityManager_ != nullptr) {
107             return abilityManager_;
108         }
109         IMSA_HILOGI("get input method service proxy");
110         sptr<ISystemAbilityManager> systemAbilityManager =
111             SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager();
112         if (systemAbilityManager == nullptr) {
113             IMSA_HILOGI("system ability manager is nullptr");
114             return nullptr;
115         }
116         auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, "");
117         if (systemAbility == nullptr) {
118             IMSA_HILOGI("system ability is nullptr");
119             return nullptr;
120         }
121         if (deathRecipient_ == nullptr) {
122             deathRecipient_ = new (std::nothrow)ImsaDeathRecipient();
123             if (deathRecipient_ == nullptr) {
124                 IMSA_HILOGE("new death recipient failed");
125                 return nullptr;
126             }
127         }
128         if ((systemAbility->IsProxyObject()) && (!systemAbility->AddDeathRecipient(deathRecipient_))) {
129             IMSA_HILOGE("failed to add death recipient.");
130             return nullptr;
131         }
132         abilityManager_ = iface_cast<IInputMethodSystemAbility>(systemAbility);
133         return abilityManager_;
134     }
135 
WorkThread()136     void InputMethodController::WorkThread()
137     {
138         while (!stop_) {
139             Message *msg = msgHandler->GetMessage();
140             switch (msg->msgId_) {
141                 case MSG_ID_INSERT_CHAR: {
142                     MessageParcel *data = msg->msgContent_;
143                     std::u16string text = data->ReadString16();
144                     IMSA_HILOGI("InputMethodController::WorkThread InsertText");
145                     std::lock_guard<std::mutex> lock(textListenerLock_);
146                     if (textListener) {
147                         textListener->InsertText(text);
148                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
149                         textFieldReplyCount_++;
150                     }
151                     break;
152                 }
153 
154                 case MSG_ID_DELETE_FORWARD: {
155                     MessageParcel *data = msg->msgContent_;
156                     int32_t length = data->ReadInt32();
157                     IMSA_HILOGI("InputMethodController::WorkThread DeleteForward");
158                     std::lock_guard<std::mutex> lock(textListenerLock_);
159                     if (textListener) {
160                         textListener->DeleteForward(length);
161                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
162                         textFieldReplyCount_++;
163                     }
164                     break;
165                 }
166                 case MSG_ID_DELETE_BACKWARD: {
167                     MessageParcel *data = msg->msgContent_;
168                     int32_t length = data->ReadInt32();
169                     IMSA_HILOGI("InputMethodController::WorkThread DeleteBackward");
170                     std::lock_guard<std::mutex> lock(textListenerLock_);
171                     if (textListener) {
172                         textListener->DeleteBackward(length);
173                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
174                         textFieldReplyCount_++;
175                     }
176                     break;
177                 }
178                 case MSG_ID_ON_INPUT_READY: {
179                     MessageParcel *data = msg->msgContent_;
180                     sptr<IRemoteObject> object = data->ReadRemoteObject();
181                     if (object) {
182                         SetInputMethodAgent(object);
183                     }
184                     break;
185                 }
186                 case MSG_ID_SEND_KEYBOARD_STATUS: {
187                     MessageParcel *data = msg->msgContent_;
188                     int32_t ret = data->ReadInt32();
189                     KeyboardInfo *info = new KeyboardInfo();
190                     info->SetKeyboardStatus(ret);
191                     IMSA_HILOGI("InputMethodController::WorkThread SendKeyboardInfo");
192                     std::lock_guard<std::mutex> lock(textListenerLock_);
193                     if (textListener) {
194                         textListener->SendKeyboardInfo(*info);
195                         DoIncrease(ret);
196                     }
197                     delete info;
198                     break;
199                 }
200                 case MSG_ID_SEND_FUNCTION_KEY: {
201                     MessageParcel *data = msg->msgContent_;
202                     int32_t ret = data->ReadInt32();
203                     KeyboardInfo *info = new KeyboardInfo();
204                     info->SetFunctionKey(ret);
205                     IMSA_HILOGI("InputMethodController::WorkThread SendKeyboardInfo");
206                     std::lock_guard<std::mutex> lock(textListenerLock_);
207                     if (textListener) {
208                         textListener->SendKeyboardInfo(*info);
209                     }
210                     delete info;
211                     break;
212                 }
213                 case MSG_ID_MOVE_CURSOR: {
214                     MessageParcel *data = msg->msgContent_;
215                     int32_t ret = data->ReadInt32();
216                     IMSA_HILOGI("InputMethodController::WorkThread MoveCursor");
217                     std::lock_guard<std::mutex> lock(textListenerLock_);
218                     if (textListener) {
219                         Direction direction = static_cast<Direction>(ret);
220                         textListener->MoveCursor(direction);
221                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
222                         textFieldReplyCount_++;
223                     }
224                     break;
225                 }
226                 case MSG_ID_ON_SWITCH_INPUT: {
227                     auto data = msg->msgContent_;
228                     Property property;
229                     SubProperty subProperty;
230                     if (!ITypesUtil::Unmarshal(*data, property, subProperty)) {
231                         IMSA_HILOGE("read property from message parcel failed");
232                         break;
233                     }
234                     OnSwitchInput(property, subProperty);
235                     break;
236                 }
237                 case MSG_ID_HANDLE_SET_SELECTION: {
238                     MessageParcel *data = msg->msgContent_;
239                     int32_t start = data->ReadInt32();
240                     int32_t end = data->ReadInt32();
241                     IMSA_HILOGI("InputMethodController::WorkThread HandleSetSelection");
242                     if (textListener) {
243                         textListener->HandleSetSelection(start, end);
244                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
245                         textFieldReplyCount_++;
246                     }
247                     break;
248                 }
249                 case MSG_ID_HANDLE_EXTEND_ACTION: {
250                     MessageParcel *data = msg->msgContent_;
251                     int32_t action = data->ReadInt32();
252                     IMSA_HILOGI("InputMethodController::WorkThread HandleExtendAction");
253                     if (textListener) {
254                         textListener->HandleExtendAction(action);
255                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
256                         textFieldReplyCount_++;
257                     }
258                     break;
259                 }
260                 case MSG_ID_HANDLE_SELECT: {
261                     MessageParcel *data = msg->msgContent_;
262                     int32_t keyCode = data->ReadInt32();
263                     int32_t cursorMoveSkip = data->ReadInt32();
264                     IMSA_HILOGI("InputMethodController::WorkThread HandleSelect");
265                     if (textListener) {
266                         textListener->HandleSelect(keyCode, cursorMoveSkip);
267                         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
268                         textFieldReplyCount_++;
269                     }
270                     break;
271                 }
272                 case MSG_ID_GET_TEXT_BEFORE_CURSOR:
273                 case MSG_ID_GET_TEXT_AFTER_CURSOR: {
274                     IMSA_HILOGI("InputMethodController::WorkThread HandleGetOperation, msgId: %{public}d", msg->msgId_);
275                     HandleGetOperation();
276                     break;
277                 }
278                 default: {
279                     IMSA_HILOGD("the message is %{public}d.", msg->msgId_);
280                     break;
281                 }
282             }
283             delete msg;
284             msg = nullptr;
285         }
286     }
287 
DoIncrease(int32_t status)288     void InputMethodController::DoIncrease(int32_t status)
289     {
290         if (status == KEYBOARD_SHOW) {
291             std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
292             textFieldReplyCount_++;
293         }
294     }
295 
QuitWorkThread()296     void InputMethodController::QuitWorkThread()
297     {
298         stop_ = true;
299         Message *msg = new Message(MessageID::MSG_ID_QUIT_WORKER_THREAD, nullptr);
300         msgHandler->SendMessage(msg);
301         if (workThreadHandler.joinable()) {
302             workThreadHandler.join();
303         }
304     }
305 
OnSwitchInput(const Property & property,const SubProperty & subProperty)306     void InputMethodController::OnSwitchInput(const Property &property, const SubProperty &subProperty)
307     {
308         IMSA_HILOGE("InputMethodController::OnSwitchInput");
309         if (imeListener_ == nullptr) {
310             IMSA_HILOGE("imeListener_ is nullptr");
311             return;
312         }
313         imeListener_->OnImeChange(property, subProperty);
314     }
315 
Attach(sptr<OnTextChangedListener> & listener)316     void InputMethodController::Attach(sptr<OnTextChangedListener> &listener)
317     {
318         Attach(listener, true);
319     }
320 
Attach(sptr<OnTextChangedListener> & listener,bool isShowKeyboard)321     void InputMethodController::Attach(sptr<OnTextChangedListener> &listener, bool isShowKeyboard)
322     {
323         InputAttribute attribute;
324         attribute.inputPattern = InputAttribute::PATTERN_TEXT;
325         Attach(listener, isShowKeyboard, attribute);
326     }
327 
Attach(sptr<OnTextChangedListener> & listener,bool isShowKeyboard,InputAttribute & attribute)328     void InputMethodController::Attach(
329         sptr<OnTextChangedListener> &listener, bool isShowKeyboard, InputAttribute &attribute)
330     {
331         {
332             std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
333             textFieldReplyCount_ = 0;
334         }
335         {
336             std::lock_guard<std::mutex> lock(textListenerLock_);
337             textListener = listener;
338         }
339         IMSA_HILOGI("InputMethodController::Attach");
340         InputmethodTrace tracer("InputMethodController Attach trace.");
341         IMSA_HILOGI("InputMethodController::Attach isShowKeyboard %{public}s", isShowKeyboard ? "true" : "false");
342         mAttribute = attribute;
343         PrepareInput(0, mClient, mInputDataChannel, mAttribute);
344         StartInput(mClient, isShowKeyboard);
345     }
346 
ShowTextInput()347     void InputMethodController::ShowTextInput()
348     {
349         IMSA_HILOGI("InputMethodController::ShowTextInput");
350         StartInput(mClient, true);
351     }
352 
HideTextInput()353     void InputMethodController::HideTextInput()
354     {
355         IMSA_HILOGD("InputMethodController::HideTextInput");
356         StopInput(mClient);
357     }
358 
HideCurrentInput()359     int32_t InputMethodController::HideCurrentInput()
360     {
361         IMSA_HILOGD("InputMethodController::HideCurrentInput");
362         auto proxy = GetSystemAbilityProxy();
363         if (proxy == nullptr) {
364             IMSA_HILOGE("proxy is nullptr");
365             return ErrorCode::ERROR_EX_NULL_POINTER;
366         }
367         return proxy->HideCurrentInputDeprecated();
368     }
369 
ShowCurrentInput()370     int32_t InputMethodController::ShowCurrentInput()
371     {
372         IMSA_HILOGI("InputMethodController::ShowCurrentInput");
373         auto proxy = GetSystemAbilityProxy();
374         if (proxy == nullptr) {
375             IMSA_HILOGE("proxy is nullptr");
376             return ErrorCode::ERROR_EX_NULL_POINTER;
377         }
378         return proxy->ShowCurrentInputDeprecated();
379     }
380 
Close()381     void InputMethodController::Close()
382     {
383         ReleaseInput(mClient);
384         InputmethodTrace tracer("InputMethodController Close trace.");
385         {
386             std::lock_guard<std::mutex> lock(textListenerLock_);
387             textListener = nullptr;
388         }
389         IMSA_HILOGI("InputMethodController::Close");
390     }
391 
PrepareInput(int32_t displayId,sptr<IInputClient> & client,sptr<IInputDataChannel> & channel,InputAttribute & attribute)392     void InputMethodController::PrepareInput(int32_t displayId, sptr<IInputClient> &client,
393         sptr<IInputDataChannel> &channel, InputAttribute &attribute)
394     {
395         IMSA_HILOGI("InputMethodController::PrepareInput");
396         auto proxy = GetSystemAbilityProxy();
397         if (proxy == nullptr) {
398             IMSA_HILOGE("proxy is nullptr");
399             return;
400         }
401         proxy->PrepareInput(displayId, client, channel, attribute);
402     }
403 
DisplayOptionalInputMethod()404     int32_t InputMethodController::DisplayOptionalInputMethod()
405     {
406         IMSA_HILOGI("InputMethodController::DisplayOptionalInputMethod");
407         auto proxy = GetSystemAbilityProxy();
408         if (proxy == nullptr) {
409             IMSA_HILOGE("proxy is nullptr");
410             return ErrorCode::ERROR_EX_NULL_POINTER;
411         }
412         return proxy->DisplayOptionalInputMethodDeprecated();
413     }
414 
ListInputMethodCommon(InputMethodStatus status,std::vector<Property> & props)415     int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector<Property> &props)
416     {
417         IMSA_HILOGI("InputMethodController::ListInputMethodCommon");
418         auto proxy = GetSystemAbilityProxy();
419         if (proxy == nullptr) {
420             IMSA_HILOGE("proxy is nullptr");
421             return ErrorCode::ERROR_EX_NULL_POINTER;
422         }
423         return proxy->ListInputMethod(status, props);
424     }
425 
ListInputMethod(std::vector<Property> & props)426     int32_t InputMethodController::ListInputMethod(std::vector<Property> &props)
427     {
428         IMSA_HILOGI("InputMethodController::listInputMethod");
429         return ListInputMethodCommon(ALL, props);
430     }
431 
ListInputMethod(bool enable,std::vector<Property> & props)432     int32_t InputMethodController::ListInputMethod(bool enable, std::vector<Property> &props)
433     {
434         IMSA_HILOGI("InputMethodController::listInputMethod enable = %{public}s", enable ? "ENABLE" : "DISABLE");
435         return ListInputMethodCommon(enable ? ENABLE : DISABLE, props);
436     }
437 
GetCurrentInputMethod()438     std::shared_ptr<Property> InputMethodController::GetCurrentInputMethod()
439     {
440         IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
441         auto proxy = GetSystemAbilityProxy();
442         if (proxy == nullptr) {
443             IMSA_HILOGE("proxy is nullptr");
444             return nullptr;
445         }
446         auto property = proxy->GetCurrentInputMethod();
447         if (property == nullptr) {
448             IMSA_HILOGE("InputMethodController::GetCurrentInputMethod property is nullptr");
449             return nullptr;
450         }
451         return property;
452     }
453 
GetCurrentInputMethodSubtype()454     std::shared_ptr<SubProperty> InputMethodController::GetCurrentInputMethodSubtype()
455     {
456         IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
457         auto proxy = GetSystemAbilityProxy();
458         if (proxy == nullptr) {
459             IMSA_HILOGE("proxy is nullptr");
460             return nullptr;
461         }
462         auto property = proxy->GetCurrentInputMethodSubtype();
463         if (property == nullptr) {
464             IMSA_HILOGE("InputMethodController::GetCurrentInputMethodSubtype property is nullptr");
465             return nullptr;
466         }
467         return property;
468     }
469 
StartInput(sptr<IInputClient> & client,bool isShowKeyboard)470     void InputMethodController::StartInput(sptr<IInputClient> &client, bool isShowKeyboard)
471     {
472         IMSA_HILOGI("InputMethodController::StartInput");
473         isStopInput = false;
474         auto proxy = GetSystemAbilityProxy();
475         if (proxy == nullptr) {
476             IMSA_HILOGE("proxy is nullptr");
477             return;
478         }
479         proxy->StartInput(client, isShowKeyboard);
480     }
481 
ReleaseInput(sptr<IInputClient> & client)482     void InputMethodController::ReleaseInput(sptr<IInputClient> &client)
483     {
484         IMSA_HILOGD("InputMethodController::ReleaseInput");
485         isStopInput = true;
486         auto proxy = GetSystemAbilityProxy();
487         if (proxy == nullptr) {
488             IMSA_HILOGE("proxy is nullptr");
489             return;
490         }
491         proxy->ReleaseInput(client);
492     }
493 
StopInput(sptr<IInputClient> & client)494     void InputMethodController::StopInput(sptr<IInputClient> &client)
495     {
496         IMSA_HILOGD("InputMethodController::StopInput");
497         isStopInput = true;
498         auto proxy = GetSystemAbilityProxy();
499         if (proxy == nullptr) {
500             IMSA_HILOGE("proxy is nullptr");
501             return;
502         }
503         proxy->StopInput(client);
504     }
505 
OnRemoteSaDied(const wptr<IRemoteObject> & remote)506     void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
507     {
508         IMSA_HILOGE("input method service death");
509         std::lock_guard<std::mutex> lock(abilityLock_);
510         abilityManager_ = nullptr;
511     }
512 
ImsaDeathRecipient()513     ImsaDeathRecipient::ImsaDeathRecipient()
514     {
515     }
516 
OnRemoteDied(const wptr<IRemoteObject> & object)517     void ImsaDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
518     {
519         InputMethodController::GetInstance()->OnRemoteSaDied(object);
520     }
521 
OnCursorUpdate(CursorInfo cursorInfo)522     void InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
523     {
524         if (isStopInput) {
525             IMSA_HILOGD("InputMethodController::OnCursorUpdate isStopInput");
526             return;
527         }
528         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
529         if (agent == nullptr) {
530             IMSA_HILOGI("InputMethodController::OnCursorUpdate agent is nullptr");
531             return;
532         }
533         if (cursorInfo_.left == cursorInfo.left && cursorInfo_.top == cursorInfo.top
534             && cursorInfo_.height == cursorInfo.height) {
535             return;
536         }
537         cursorInfo_ = cursorInfo;
538         agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
539     }
540 
OnSelectionChange(std::u16string text,int start,int end)541     void InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
542     {
543         IMSA_HILOGI("size: %{public}zu, start: %{public}d, end: %{public}d, replyCount: %{public}d", text.size(),
544             start, end, textFieldReplyCount_);
545         if (isStopInput) {
546             IMSA_HILOGD("InputMethodController::OnSelectionChange isStopInput");
547             return;
548         }
549         {
550             std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
551             if (textFieldReplyCount_ > 0
552                 && (text.size() != mTextString.size() || start != mSelectNewBegin || end != mSelectNewEnd)) {
553                 textFieldReplyCount_--;
554             }
555             if (textFieldReplyCount_ == 0) {
556                 textFieldReplyCountCv_.notify_one();
557             }
558         }
559         if (mTextString == text && mSelectNewBegin == start && mSelectNewEnd == end) {
560             return;
561         }
562         mTextString = text;
563         mSelectOldBegin = mSelectNewBegin;
564         mSelectOldEnd = mSelectNewEnd;
565         mSelectNewBegin = start;
566         mSelectNewEnd = end;
567         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
568         if (agent == nullptr) {
569             IMSA_HILOGI("InputMethodController::OnSelectionChange agent is nullptr");
570             return;
571         }
572         agent->OnSelectionChange(mTextString, mSelectOldBegin, mSelectOldEnd, mSelectNewBegin, mSelectNewEnd);
573     }
574 
OnConfigurationChange(Configuration info)575     void InputMethodController::OnConfigurationChange(Configuration info)
576     {
577         IMSA_HILOGI("InputMethodController::OnConfigurationChange");
578         enterKeyType_ = static_cast<uint32_t>(info.GetEnterKeyType());
579         inputPattern_ = static_cast<uint32_t>(info.GetTextInputType());
580     }
581 
HandleGetOperation()582     void InputMethodController::HandleGetOperation()
583     {
584         IMSA_HILOGI("InputMethodController::start");
585         if (isStopInput) {
586             IMSA_HILOGE("InputMethodController::text filed is not Focused");
587             mSelectNewEnd = -1;
588             mInputDataChannel->NotifyGetOperationCompletion();
589             return;
590         }
591         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
592         auto ret = textFieldReplyCountCv_.wait_for(
593             numLock, std::chrono::milliseconds(WAIT_TIME), [this] { return textFieldReplyCount_ == 0; });
594         if (!ret) {
595             IMSA_HILOGE("InputMethodController::timeout");
596             // timeout,reset the waitOnSelectionChangeNum_ to eliminate the impact on subsequent processing
597             textFieldReplyCount_ = 0;
598         }
599         IMSA_HILOGI("InputMethodController::notify");
600         mInputDataChannel->NotifyGetOperationCompletion();
601     }
602 
IsCorrectParam(int32_t number)603     bool InputMethodController::IsCorrectParam(int32_t number)
604     {
605         if (mTextString.size() > INT_MAX || number < 0 || mSelectNewEnd < 0 || mSelectNewBegin < 0) {
606             IMSA_HILOGE("InputMethodController::param error, number: %{public}d, begin: %{public}d, end: %{public}d",
607                 number, mSelectNewBegin, mSelectNewEnd);
608             return false;
609         }
610         if (mSelectNewBegin > mSelectNewEnd) {
611             int32_t temp = mSelectNewEnd;
612             mSelectNewEnd = mSelectNewBegin;
613             mSelectNewBegin = temp;
614         }
615         if (static_cast<size_t>(mSelectNewEnd) > mTextString.size()) {
616             IMSA_HILOGE("InputMethodController::param error, end: %{public}d, size: %{public}zu", mSelectNewEnd,
617                 mTextString.size());
618             return false;
619         }
620         return true;
621     }
622 
GetTextBeforeCursor(int32_t number,std::u16string & text)623     int32_t InputMethodController::GetTextBeforeCursor(int32_t number, std::u16string &text)
624     {
625         IMSA_HILOGI("InputMethodController::GetTextBeforeCursor");
626         text = u"";
627         if (!IsCorrectParam(number)) {
628             return ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED;
629         }
630         int32_t startPos = (number <= mSelectNewBegin ? (mSelectNewBegin - number) : 0);
631         int32_t length = (number <= mSelectNewBegin ? number : mSelectNewBegin);
632         text = mTextString.substr(startPos, length);
633         return ErrorCode::NO_ERROR;
634     }
635 
GetTextAfterCursor(int32_t number,std::u16string & text)636     int32_t InputMethodController::GetTextAfterCursor(int32_t number, std::u16string &text)
637     {
638         IMSA_HILOGI("InputMethodController::GetTextAfterCursor");
639         text = u"";
640         if (!IsCorrectParam(number)) {
641             return ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED;
642         }
643         text = mTextString.substr(mSelectNewEnd, number);
644         return ErrorCode::NO_ERROR;
645     }
646 
dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)647     bool InputMethodController::dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)
648     {
649         IMSA_HILOGI("InputMethodController::start");
650         if (isStopInput) {
651             IMSA_HILOGD("InputMethodController::dispatchKeyEvent isStopInput");
652             return false;
653         }
654         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
655         if (agent == nullptr) {
656             IMSA_HILOGI("InputMethodController::dispatchKeyEvent agent is nullptr");
657             return false;
658         }
659         MessageParcel data;
660         if (!(data.WriteInterfaceToken(agent->GetDescriptor())
661             && data.WriteInt32(keyEvent->GetKeyCode())
662             && data.WriteInt32(keyEvent->GetKeyAction()))) {
663             return false;
664         }
665 
666         return agent->DispatchKeyEvent(data);
667     }
668 
GetEnterKeyType(int32_t & keyType)669     int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
670     {
671         IMSA_HILOGI("InputMethodController::GetEnterKeyType");
672         keyType = enterKeyType_;
673         return ErrorCode::NO_ERROR;
674     }
675 
GetInputPattern(int32_t & inputpattern)676     int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
677     {
678         IMSA_HILOGI("InputMethodController::GetInputPattern");
679         inputpattern = inputPattern_;
680         return ErrorCode::NO_ERROR;
681     }
682 
SetCallingWindow(uint32_t windowId)683     void InputMethodController::SetCallingWindow(uint32_t windowId)
684     {
685         if (isStopInput) {
686             IMSA_HILOGD("InputMethodController::SetCallingWindow isStopInput");
687             return;
688         }
689         IMSA_HILOGI("InputMethodController::SetCallingWindow windowId = %{public}d", windowId);
690         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
691         if (agent == nullptr) {
692             IMSA_HILOGI("InputMethodController::SetCallingWindow agent is nullptr");
693             return;
694         }
695         agent->SetCallingWindow(windowId);
696     }
697 
SetInputMethodAgent(sptr<IRemoteObject> & object)698     void InputMethodController::SetInputMethodAgent(sptr<IRemoteObject> &object)
699     {
700         IMSA_HILOGI("run in SetInputMethodAgent");
701         std::lock_guard<std::mutex> lock(agentLock_);
702         std::shared_ptr<IInputMethodAgent> agent = std::make_shared<InputMethodAgentProxy>(object);
703         if (agent == nullptr) {
704             IMSA_HILOGI("InputMethodController::SetInputMethodAgent agent is nullptr");
705             return;
706         }
707         mAgent = agent;
708     }
709 
GetInputMethodAgent()710     std::shared_ptr<IInputMethodAgent> InputMethodController::GetInputMethodAgent()
711     {
712         std::lock_guard<std::mutex> lock(agentLock_);
713         return mAgent;
714     }
715 
ShowSoftKeyboard()716     int32_t InputMethodController::ShowSoftKeyboard()
717     {
718         IMSA_HILOGI("InputMethodController ShowSoftKeyboard");
719         auto proxy = GetSystemAbilityProxy();
720         if (proxy == nullptr) {
721             IMSA_HILOGE("proxy is nullptr");
722             return ErrorCode::ERROR_EX_NULL_POINTER;
723         }
724         return proxy->ShowCurrentInput();
725     }
726 
HideSoftKeyboard()727     int32_t InputMethodController::HideSoftKeyboard()
728     {
729         IMSA_HILOGI("InputMethodController HideSoftKeyboard");
730         auto proxy = GetSystemAbilityProxy();
731         if (proxy == nullptr) {
732             IMSA_HILOGE("proxy is nullptr");
733             return ErrorCode::ERROR_EX_NULL_POINTER;
734         }
735         return proxy->HideCurrentInput();
736     }
737 
StopInputSession()738     int32_t InputMethodController::StopInputSession()
739     {
740         IMSA_HILOGI("InputMethodController HideSoftKeyboard");
741         isStopInput = true;
742         auto proxy = GetSystemAbilityProxy();
743         if (proxy == nullptr) {
744             IMSA_HILOGE("proxy is nullptr");
745             return ErrorCode::ERROR_EX_NULL_POINTER;
746         }
747         return proxy->StopInputSession();
748     }
749 
ShowOptionalInputMethod()750     int32_t InputMethodController::ShowOptionalInputMethod()
751     {
752         IMSA_HILOGI("InputMethodController::ShowOptionalInputMethod");
753         auto proxy = GetSystemAbilityProxy();
754         if (proxy == nullptr) {
755             IMSA_HILOGE("proxy is nullptr");
756             return ErrorCode::ERROR_EX_NULL_POINTER;
757         }
758         return proxy->DisplayOptionalInputMethod();
759     }
760 
ListInputMethodSubtype(const Property & property,std::vector<SubProperty> & subProps)761     int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps)
762     {
763         IMSA_HILOGI("InputMethodController::ListInputMethodSubtype");
764         auto proxy = GetSystemAbilityProxy();
765         if (proxy == nullptr) {
766             IMSA_HILOGE("proxy is nullptr");
767             return ErrorCode::ERROR_EX_NULL_POINTER;
768         }
769         return proxy->ListInputMethodSubtype(property.name, subProps);
770     }
771 
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)772     int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
773     {
774         IMSA_HILOGI("InputMethodController::ListCurrentInputMethodSubtype");
775         auto proxy = GetSystemAbilityProxy();
776         if (proxy == nullptr) {
777             IMSA_HILOGE("proxy is nullptr");
778             return ErrorCode::ERROR_EX_NULL_POINTER;
779         }
780         return proxy->ListCurrentInputMethodSubtype(subProps);
781     }
782 
SwitchInputMethod(const std::string & name,const std::string & subName)783     int32_t InputMethodController::SwitchInputMethod(const std::string &name, const std::string &subName)
784     {
785         IMSA_HILOGI("InputMethodController::SwitchInputMethod");
786         auto proxy = GetSystemAbilityProxy();
787         if (proxy == nullptr) {
788             IMSA_HILOGE("proxy is nullptr");
789             return ErrorCode::ERROR_EX_NULL_POINTER;
790         }
791         return proxy->SwitchInputMethod(name, subName);
792     }
793 } // namespace MiscServices
794 } // namespace OHOS
795