• 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(sptr<OnTextChangedListener> &listener, bool isShowKeyboard,
329                                         InputAttribute &attribute)
330     {
331         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
332         textFieldReplyCount_ = 0;
333         {
334             std::lock_guard<std::mutex> lock(textListenerLock_);
335             textListener = listener;
336         }
337         IMSA_HILOGI("InputMethodController::Attach");
338         InputmethodTrace tracer("InputMethodController Attach trace.");
339         IMSA_HILOGI("InputMethodController::Attach isShowKeyboard %{public}s", isShowKeyboard ? "true" : "false");
340         mAttribute = attribute;
341         PrepareInput(0, mClient, mInputDataChannel, mAttribute);
342         StartInput(mClient, isShowKeyboard);
343     }
344 
ShowTextInput()345     void InputMethodController::ShowTextInput()
346     {
347         IMSA_HILOGI("InputMethodController::ShowTextInput");
348         StartInput(mClient, true);
349     }
350 
HideTextInput()351     void InputMethodController::HideTextInput()
352     {
353         IMSA_HILOGD("InputMethodController::HideTextInput");
354         StopInput(mClient);
355     }
356 
HideCurrentInput()357     int32_t InputMethodController::HideCurrentInput()
358     {
359         IMSA_HILOGD("InputMethodController::HideCurrentInput");
360         auto proxy = GetSystemAbilityProxy();
361         if (proxy == nullptr) {
362             IMSA_HILOGE("proxy is nullptr");
363             return ErrorCode::ERROR_EX_NULL_POINTER;
364         }
365         return proxy->HideCurrentInputDeprecated();
366     }
367 
ShowCurrentInput()368     int32_t InputMethodController::ShowCurrentInput()
369     {
370         IMSA_HILOGI("InputMethodController::ShowCurrentInput");
371         auto proxy = GetSystemAbilityProxy();
372         if (proxy == nullptr) {
373             IMSA_HILOGE("proxy is nullptr");
374             return ErrorCode::ERROR_EX_NULL_POINTER;
375         }
376         return proxy->ShowCurrentInputDeprecated();
377     }
378 
Close()379     void InputMethodController::Close()
380     {
381         ReleaseInput(mClient);
382         InputmethodTrace tracer("InputMethodController Close trace.");
383         {
384             std::lock_guard<std::mutex> lock(textListenerLock_);
385             textListener = nullptr;
386         }
387         IMSA_HILOGI("InputMethodController::Close");
388     }
389 
PrepareInput(int32_t displayId,sptr<IInputClient> & client,sptr<IInputDataChannel> & channel,InputAttribute & attribute)390     void InputMethodController::PrepareInput(int32_t displayId, sptr<IInputClient> &client,
391         sptr<IInputDataChannel> &channel, InputAttribute &attribute)
392     {
393         IMSA_HILOGI("InputMethodController::PrepareInput");
394         auto proxy = GetSystemAbilityProxy();
395         if (proxy == nullptr) {
396             IMSA_HILOGE("proxy is nullptr");
397             return;
398         }
399         proxy->PrepareInput(displayId, client, channel, attribute);
400     }
401 
DisplayOptionalInputMethod()402     int32_t InputMethodController::DisplayOptionalInputMethod()
403     {
404         IMSA_HILOGI("InputMethodController::DisplayOptionalInputMethod");
405         auto proxy = GetSystemAbilityProxy();
406         if (proxy == nullptr) {
407             IMSA_HILOGE("proxy is nullptr");
408             return ErrorCode::ERROR_EX_NULL_POINTER;
409         }
410         return proxy->DisplayOptionalInputMethodDeprecated();
411     }
412 
ListInputMethodCommon(InputMethodStatus status,std::vector<Property> & props)413     int32_t InputMethodController::ListInputMethodCommon(InputMethodStatus status, std::vector<Property> &props)
414     {
415         IMSA_HILOGI("InputMethodController::ListInputMethodCommon");
416         auto proxy = GetSystemAbilityProxy();
417         if (proxy == nullptr) {
418             IMSA_HILOGE("proxy is nullptr");
419             return ErrorCode::ERROR_EX_NULL_POINTER;
420         }
421         return proxy->ListInputMethod(status, props);
422     }
423 
ListInputMethod(std::vector<Property> & props)424     int32_t InputMethodController::ListInputMethod(std::vector<Property> &props)
425     {
426         IMSA_HILOGI("InputMethodController::listInputMethod");
427         return ListInputMethodCommon(ALL, props);
428     }
429 
ListInputMethod(bool enable,std::vector<Property> & props)430     int32_t InputMethodController::ListInputMethod(bool enable, std::vector<Property> &props)
431     {
432         IMSA_HILOGI("InputMethodController::listInputMethod enable = %{public}s", enable ? "ENABLE" : "DISABLE");
433         return ListInputMethodCommon(enable ? ENABLE : DISABLE, props);
434     }
435 
GetCurrentInputMethod()436     std::shared_ptr<Property> InputMethodController::GetCurrentInputMethod()
437     {
438         IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
439         auto proxy = GetSystemAbilityProxy();
440         if (proxy == nullptr) {
441             IMSA_HILOGE("proxy is nullptr");
442             return nullptr;
443         }
444         auto property = proxy->GetCurrentInputMethod();
445         if (property == nullptr) {
446             IMSA_HILOGE("InputMethodController::GetCurrentInputMethod property is nullptr");
447             return nullptr;
448         }
449         return property;
450     }
451 
GetCurrentInputMethodSubtype()452     std::shared_ptr<SubProperty> InputMethodController::GetCurrentInputMethodSubtype()
453     {
454         IMSA_HILOGD("InputMethodController::GetCurrentInputMethod");
455         auto proxy = GetSystemAbilityProxy();
456         if (proxy == nullptr) {
457             IMSA_HILOGE("proxy is nullptr");
458             return nullptr;
459         }
460         auto property = proxy->GetCurrentInputMethodSubtype();
461         if (property == nullptr) {
462             IMSA_HILOGE("InputMethodController::GetCurrentInputMethodSubtype property is nullptr");
463             return nullptr;
464         }
465         return property;
466     }
467 
StartInput(sptr<IInputClient> & client,bool isShowKeyboard)468     void InputMethodController::StartInput(sptr<IInputClient> &client, bool isShowKeyboard)
469     {
470         IMSA_HILOGI("InputMethodController::StartInput");
471         isStopInput = false;
472         auto proxy = GetSystemAbilityProxy();
473         if (proxy == nullptr) {
474             IMSA_HILOGE("proxy is nullptr");
475             return;
476         }
477         proxy->StartInput(client, isShowKeyboard);
478     }
479 
ReleaseInput(sptr<IInputClient> & client)480     void InputMethodController::ReleaseInput(sptr<IInputClient> &client)
481     {
482         IMSA_HILOGD("InputMethodController::ReleaseInput");
483         isStopInput = true;
484         auto proxy = GetSystemAbilityProxy();
485         if (proxy == nullptr) {
486             IMSA_HILOGE("proxy is nullptr");
487             return;
488         }
489         proxy->ReleaseInput(client);
490     }
491 
StopInput(sptr<IInputClient> & client)492     void InputMethodController::StopInput(sptr<IInputClient> &client)
493     {
494         IMSA_HILOGD("InputMethodController::StopInput");
495         isStopInput = true;
496         auto proxy = GetSystemAbilityProxy();
497         if (proxy == nullptr) {
498             IMSA_HILOGE("proxy is nullptr");
499             return;
500         }
501         proxy->StopInput(client);
502     }
503 
OnRemoteSaDied(const wptr<IRemoteObject> & remote)504     void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote)
505     {
506         IMSA_HILOGE("input method service death");
507         std::lock_guard<std::mutex> lock(abilityLock_);
508         abilityManager_ = nullptr;
509     }
510 
ImsaDeathRecipient()511     ImsaDeathRecipient::ImsaDeathRecipient()
512     {
513     }
514 
OnRemoteDied(const wptr<IRemoteObject> & object)515     void ImsaDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object)
516     {
517         InputMethodController::GetInstance()->OnRemoteSaDied(object);
518     }
519 
OnCursorUpdate(CursorInfo cursorInfo)520     void InputMethodController::OnCursorUpdate(CursorInfo cursorInfo)
521     {
522         if (isStopInput) {
523             IMSA_HILOGD("InputMethodController::OnCursorUpdate isStopInput");
524             return;
525         }
526         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
527         if (agent == nullptr) {
528             IMSA_HILOGI("InputMethodController::OnCursorUpdate agent is nullptr");
529             return;
530         }
531         if (cursorInfo_.left == cursorInfo.left && cursorInfo_.top == cursorInfo.top
532             && cursorInfo_.height == cursorInfo.height) {
533             return;
534         }
535         cursorInfo_ = cursorInfo;
536         agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height);
537     }
538 
OnSelectionChange(std::u16string text,int start,int end)539     void InputMethodController::OnSelectionChange(std::u16string text, int start, int end)
540     {
541         IMSA_HILOGI("size: %{public}zu, start: %{public}d, end: %{public}d, replyCount: %{public}d", text.size(), start,
542             end, textFieldReplyCount_);
543         if (isStopInput) {
544             IMSA_HILOGD("InputMethodController::OnSelectionChange isStopInput");
545             return;
546         }
547         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
548         if (textFieldReplyCount_ > 0
549             && (text.size() != mTextString.size() || start != mSelectNewBegin || end != mSelectNewEnd)) {
550             textFieldReplyCount_--;
551         }
552         if (textFieldReplyCount_ == 0) {
553             textFieldReplyCountCv_.notify_one();
554         }
555         if (mTextString == text && mSelectNewBegin == start && mSelectNewEnd == end) {
556             return;
557         }
558         mTextString = text;
559         mSelectOldBegin = mSelectNewBegin;
560         mSelectOldEnd = mSelectNewEnd;
561         mSelectNewBegin = start;
562         mSelectNewEnd = end;
563         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
564         if (agent == nullptr) {
565             IMSA_HILOGI("InputMethodController::OnSelectionChange agent is nullptr");
566             return;
567         }
568         agent->OnSelectionChange(mTextString, mSelectOldBegin, mSelectOldEnd, mSelectNewBegin, mSelectNewEnd);
569     }
570 
OnConfigurationChange(Configuration info)571     void InputMethodController::OnConfigurationChange(Configuration info)
572     {
573         IMSA_HILOGI("InputMethodController::OnConfigurationChange");
574         enterKeyType_ = static_cast<uint32_t>(info.GetEnterKeyType());
575         inputPattern_ = static_cast<uint32_t>(info.GetTextInputType());
576     }
577 
HandleGetOperation()578     void InputMethodController::HandleGetOperation()
579     {
580         IMSA_HILOGI("InputMethodController::start");
581         if (isStopInput) {
582             IMSA_HILOGE("InputMethodController::text filed is not Focused");
583             mSelectNewEnd = -1;
584             mInputDataChannel->NotifyGetOperationCompletion();
585             return;
586         }
587         std::unique_lock<std::mutex> numLock(textFieldReplyCountLock_);
588         auto ret = textFieldReplyCountCv_.wait_for(
589             numLock, std::chrono::milliseconds(WAIT_TIME), [this] { return textFieldReplyCount_ == 0; });
590         if (!ret) {
591             IMSA_HILOGE("InputMethodController::timeout");
592             // timeout,reset the waitOnSelectionChangeNum_ to eliminate the impact on subsequent processing
593             textFieldReplyCount_ = 0;
594         }
595         IMSA_HILOGI("InputMethodController::notify");
596         mInputDataChannel->NotifyGetOperationCompletion();
597     }
598 
IsCorrectParam(int32_t number)599     bool InputMethodController::IsCorrectParam(int32_t number)
600     {
601         if (mTextString.size() > INT_MAX || number < 0 || mSelectNewEnd < 0 || mSelectNewBegin < 0) {
602             IMSA_HILOGE("InputMethodController::param error, number: %{public}d, begin: %{public}d, end: %{public}d",
603                 number, mSelectNewBegin, mSelectNewEnd);
604             return false;
605         }
606         if (mSelectNewBegin > mSelectNewEnd) {
607             int32_t temp = mSelectNewEnd;
608             mSelectNewEnd = mSelectNewBegin;
609             mSelectNewBegin = temp;
610         }
611         if (static_cast<size_t>(mSelectNewEnd) > mTextString.size()) {
612             IMSA_HILOGE("InputMethodController::param error, end: %{public}d, size: %{public}zu", mSelectNewEnd,
613                 mTextString.size());
614             return false;
615         }
616         return true;
617     }
618 
GetTextBeforeCursor(int32_t number,std::u16string & text)619     int32_t InputMethodController::GetTextBeforeCursor(int32_t number, std::u16string &text)
620     {
621         IMSA_HILOGI("InputMethodController::GetTextBeforeCursor");
622         text = u"";
623         if (!IsCorrectParam(number)) {
624             return ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED;
625         }
626         int32_t startPos = (number <= mSelectNewBegin ? (mSelectNewBegin - number) : 0);
627         int32_t length = (number <= mSelectNewBegin ? number : mSelectNewBegin);
628         text = mTextString.substr(startPos, length);
629         return ErrorCode::NO_ERROR;
630     }
631 
GetTextAfterCursor(int32_t number,std::u16string & text)632     int32_t InputMethodController::GetTextAfterCursor(int32_t number, std::u16string &text)
633     {
634         IMSA_HILOGI("InputMethodController::GetTextAfterCursor");
635         text = u"";
636         if (!IsCorrectParam(number)) {
637             return ErrorCode::ERROR_CONTROLLER_INVOKING_FAILED;
638         }
639         text = mTextString.substr(mSelectNewEnd, number);
640         return ErrorCode::NO_ERROR;
641     }
642 
dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)643     bool InputMethodController::dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)
644     {
645         IMSA_HILOGI("InputMethodController::start");
646         if (isStopInput) {
647             IMSA_HILOGD("InputMethodController::dispatchKeyEvent isStopInput");
648             return false;
649         }
650         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
651         if (agent == nullptr) {
652             IMSA_HILOGI("InputMethodController::dispatchKeyEvent agent is nullptr");
653             return false;
654         }
655         MessageParcel data;
656         if (!(data.WriteInterfaceToken(agent->GetDescriptor())
657             && data.WriteInt32(keyEvent->GetKeyCode())
658             && data.WriteInt32(keyEvent->GetKeyAction()))) {
659             return false;
660         }
661 
662         return agent->DispatchKeyEvent(data);
663     }
664 
GetEnterKeyType(int32_t & keyType)665     int32_t InputMethodController::GetEnterKeyType(int32_t &keyType)
666     {
667         IMSA_HILOGI("InputMethodController::GetEnterKeyType");
668         keyType = enterKeyType_;
669         return ErrorCode::NO_ERROR;
670     }
671 
GetInputPattern(int32_t & inputpattern)672     int32_t InputMethodController::GetInputPattern(int32_t &inputpattern)
673     {
674         IMSA_HILOGI("InputMethodController::GetInputPattern");
675         inputpattern = inputPattern_;
676         return ErrorCode::NO_ERROR;
677     }
678 
SetCallingWindow(uint32_t windowId)679     void InputMethodController::SetCallingWindow(uint32_t windowId)
680     {
681         if (isStopInput) {
682             IMSA_HILOGD("InputMethodController::SetCallingWindow isStopInput");
683             return;
684         }
685         IMSA_HILOGI("InputMethodController::SetCallingWindow windowId = %{public}d", windowId);
686         std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent();
687         if (agent == nullptr) {
688             IMSA_HILOGI("InputMethodController::SetCallingWindow agent is nullptr");
689             return;
690         }
691         agent->SetCallingWindow(windowId);
692     }
693 
SetInputMethodAgent(sptr<IRemoteObject> & object)694     void InputMethodController::SetInputMethodAgent(sptr<IRemoteObject> &object)
695     {
696         IMSA_HILOGI("run in SetInputMethodAgent");
697         std::lock_guard<std::mutex> lock(agentLock_);
698         std::shared_ptr<IInputMethodAgent> agent = std::make_shared<InputMethodAgentProxy>(object);
699         if (agent == nullptr) {
700             IMSA_HILOGI("InputMethodController::SetInputMethodAgent agent is nullptr");
701             return;
702         }
703         mAgent = agent;
704     }
705 
GetInputMethodAgent()706     std::shared_ptr<IInputMethodAgent> InputMethodController::GetInputMethodAgent()
707     {
708         std::lock_guard<std::mutex> lock(agentLock_);
709         return mAgent;
710     }
711 
ShowSoftKeyboard()712     int32_t InputMethodController::ShowSoftKeyboard()
713     {
714         IMSA_HILOGI("InputMethodController ShowSoftKeyboard");
715         auto proxy = GetSystemAbilityProxy();
716         if (proxy == nullptr) {
717             IMSA_HILOGE("proxy is nullptr");
718             return ErrorCode::ERROR_EX_NULL_POINTER;
719         }
720         return proxy->ShowCurrentInput();
721     }
722 
HideSoftKeyboard()723     int32_t InputMethodController::HideSoftKeyboard()
724     {
725         IMSA_HILOGI("InputMethodController HideSoftKeyboard");
726         auto proxy = GetSystemAbilityProxy();
727         if (proxy == nullptr) {
728             IMSA_HILOGE("proxy is nullptr");
729             return ErrorCode::ERROR_EX_NULL_POINTER;
730         }
731         return proxy->HideCurrentInput();
732     }
733 
StopInputSession()734     int32_t InputMethodController::StopInputSession()
735     {
736         IMSA_HILOGI("InputMethodController HideSoftKeyboard");
737         isStopInput = true;
738         auto proxy = GetSystemAbilityProxy();
739         if (proxy == nullptr) {
740             IMSA_HILOGE("proxy is nullptr");
741             return ErrorCode::ERROR_EX_NULL_POINTER;
742         }
743         return proxy->StopInputSession();
744     }
745 
ShowOptionalInputMethod()746     int32_t InputMethodController::ShowOptionalInputMethod()
747     {
748         IMSA_HILOGI("InputMethodController::ShowOptionalInputMethod");
749         auto proxy = GetSystemAbilityProxy();
750         if (proxy == nullptr) {
751             IMSA_HILOGE("proxy is nullptr");
752             return ErrorCode::ERROR_EX_NULL_POINTER;
753         }
754         return proxy->DisplayOptionalInputMethod();
755     }
756 
ListInputMethodSubtype(const Property & property,std::vector<SubProperty> & subProps)757     int32_t InputMethodController::ListInputMethodSubtype(const Property &property, std::vector<SubProperty> &subProps)
758     {
759         IMSA_HILOGI("InputMethodController::ListInputMethodSubtype");
760         auto proxy = GetSystemAbilityProxy();
761         if (proxy == nullptr) {
762             IMSA_HILOGE("proxy is nullptr");
763             return ErrorCode::ERROR_EX_NULL_POINTER;
764         }
765         return proxy->ListInputMethodSubtype(property.name, subProps);
766     }
767 
ListCurrentInputMethodSubtype(std::vector<SubProperty> & subProps)768     int32_t InputMethodController::ListCurrentInputMethodSubtype(std::vector<SubProperty> &subProps)
769     {
770         IMSA_HILOGI("InputMethodController::ListCurrentInputMethodSubtype");
771         auto proxy = GetSystemAbilityProxy();
772         if (proxy == nullptr) {
773             IMSA_HILOGE("proxy is nullptr");
774             return ErrorCode::ERROR_EX_NULL_POINTER;
775         }
776         return proxy->ListCurrentInputMethodSubtype(subProps);
777     }
778 
SwitchInputMethod(const std::string & name,const std::string & subName)779     int32_t InputMethodController::SwitchInputMethod(const std::string &name, const std::string &subName)
780     {
781         IMSA_HILOGI("InputMethodController::SwitchInputMethod");
782         auto proxy = GetSystemAbilityProxy();
783         if (proxy == nullptr) {
784             IMSA_HILOGE("proxy is nullptr");
785             return ErrorCode::ERROR_EX_NULL_POINTER;
786         }
787         return proxy->SwitchInputMethod(name, subName);
788     }
789 } // namespace MiscServices
790 } // namespace OHOS
791