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 #include "iservice_registry.h" 18 #include "system_ability_definition.h" 19 #include "global.h" 20 21 namespace OHOS { 22 namespace MiscServices { 23 using namespace MessageID; 24 sptr<InputMethodController> InputMethodController::instance_; 25 std::mutex InputMethodController::instanceLock_; 26 InputMethodController()27 InputMethodController::InputMethodController() : stop_(false) 28 { 29 IMSA_HILOGI("InputMethodController structure"); 30 Initialize(); 31 } 32 ~InputMethodController()33 InputMethodController::~InputMethodController() 34 { 35 if (msgHandler != nullptr) { 36 delete msgHandler; 37 msgHandler = nullptr; 38 stop_ = false; 39 } 40 } 41 GetInstance()42 sptr<InputMethodController> InputMethodController::GetInstance() 43 { 44 if (instance_ == nullptr) { 45 std::lock_guard<std::mutex> autoLock(instanceLock_); 46 if (instance_ == nullptr) { 47 IMSA_HILOGI("InputMethodController::GetInstance instance_ is nullptr"); 48 instance_ = new InputMethodController(); 49 } 50 } 51 return instance_; 52 } 53 Initialize()54 bool InputMethodController::Initialize() 55 { 56 msgHandler = new MessageHandler(); 57 58 mClient = new InputClientStub(); 59 mClient->SetHandler(msgHandler); 60 61 mInputDataChannel = new InputDataChannelStub(); 62 mInputDataChannel->SetHandler(msgHandler); 63 64 workThreadHandler = std::thread([this] {WorkThread();}); 65 mAttribute.SetInputPattern(InputAttribute::PATTERN_TEXT); 66 67 textListener = nullptr; 68 PrepareInput(0, mClient, mInputDataChannel, mAttribute); 69 return true; 70 } 71 GetSystemAbilityProxy()72 sptr<IInputMethodSystemAbility> InputMethodController::GetSystemAbilityProxy() 73 { 74 IMSA_HILOGD("start"); 75 std::lock_guard<std::mutex> lock(abilityLock_); 76 if (systemAbility_ != nullptr) { 77 return systemAbility_; 78 } 79 IMSA_HILOGI("get input method service proxy"); 80 sptr<ISystemAbilityManager> systemAbilityManager = 81 SystemAbilityManagerClient::GetInstance().GetSystemAbilityManager(); 82 if (systemAbilityManager == nullptr) { 83 IMSA_HILOGE("systemAbilityManager is nullptr"); 84 return nullptr; 85 } 86 auto systemAbility = systemAbilityManager->GetSystemAbility(INPUT_METHOD_SYSTEM_ABILITY_ID, ""); 87 if (systemAbility == nullptr) { 88 IMSA_HILOGE("systemAbility is nullptr"); 89 return nullptr; 90 } 91 if (deathRecipient_ == nullptr) { 92 deathRecipient_ = new (std::nothrow) ImsaDeathRecipient(); 93 if (deathRecipient_ == nullptr) { 94 IMSA_HILOGE("failed to new death recipient"); 95 return nullptr; 96 } 97 } 98 if (systemAbility->IsProxyObject() && (!systemAbility->AddDeathRecipient(deathRecipient_))) { 99 IMSA_HILOGE("failed to add death recipient"); 100 return nullptr; 101 } 102 systemAbility_ = iface_cast<IInputMethodSystemAbility>(systemAbility); 103 return systemAbility_; 104 } 105 WorkThread()106 void InputMethodController::WorkThread() 107 { 108 while (!stop_) { 109 Message *msg = msgHandler->GetMessage(); 110 switch (msg->msgId_) { 111 case MSG_ID_INSERT_CHAR: { 112 MessageParcel *data = msg->msgContent_; 113 std::u16string text = data->ReadString16(); 114 if (textListener != nullptr) { 115 textListener->InsertText(text); 116 } 117 break; 118 } 119 120 case MSG_ID_DELETE_FORWARD: { 121 IMSA_HILOGI("InputMethodController::MSG_ID_DELETE_FORWARD"); 122 MessageParcel *data = msg->msgContent_; 123 int32_t length = data->ReadInt32(); 124 if (textListener != nullptr) { 125 textListener->DeleteForward(length); 126 } 127 break; 128 } 129 case MSG_ID_DELETE_BACKWARD: { 130 IMSA_HILOGI("InputMethodController::MSG_ID_DELETE_BACKWARD"); 131 MessageParcel *data = msg->msgContent_; 132 int32_t length = data->ReadInt32(); 133 if (textListener != nullptr) { 134 textListener->DeleteBackward(length); 135 } 136 break; 137 } 138 case MSG_ID_SET_DISPLAY_MODE: { 139 MessageParcel *data = msg->msgContent_; 140 int32_t ret = data->ReadInt32(); 141 IMSA_HILOGI("MSG_ID_SET_DISPLAY_MODE : %{public}d", ret); 142 break; 143 } 144 case MSG_ID_ON_INPUT_READY: { 145 MessageParcel *data = msg->msgContent_; 146 sptr<IRemoteObject> object = data->ReadRemoteObject(); 147 if (object != nullptr) { 148 SetInputMethodAgent(object); 149 } 150 break; 151 } 152 case MSG_ID_EXIT_SERVICE: { 153 MessageParcel *data = msg->msgContent_; 154 int32_t ret = data->ReadInt32(); 155 textListener = nullptr; 156 IMSA_HILOGI("MSG_ID_EXIT_SERVICE : %{public}d", ret); 157 break; 158 } 159 case MSG_ID_SEND_KEYBOARD_STATUS: { 160 MessageParcel *data = msg->msgContent_; 161 int32_t ret = data->ReadInt32(); 162 IMSA_HILOGI("MSG_ID_SEND_KEYBOARD_STATUS : %{public}d", ret); 163 KeyboardInfo *info = new KeyboardInfo(); 164 info->SetKeyboardStatus(ret); 165 if (textListener != nullptr) { 166 textListener->SendKeyboardInfo(*info); 167 } 168 delete info; 169 break; 170 } 171 case MSG_ID_SEND_FUNCTION_KEY: { 172 MessageParcel *data = msg->msgContent_; 173 int32_t ret = data->ReadInt32(); 174 IMSA_HILOGI("MSG_ID_SEND_FUNCTION_KEY : %{public}d", ret); 175 KeyboardInfo *info = new KeyboardInfo(); 176 info->SetFunctionKey(ret); 177 if (textListener != nullptr) { 178 textListener->SendKeyboardInfo(*info); 179 } 180 delete info; 181 break; 182 } 183 case MSG_ID_MOVE_CURSOR: { 184 MessageParcel *data = msg->msgContent_; 185 int32_t ret = data->ReadInt32(); 186 IMSA_HILOGI("MSG_ID_MOVE_CURSOR : %{public}d", ret); 187 if (textListener != nullptr) { 188 Direction direction = static_cast<Direction>(ret); 189 textListener->MoveCursor(direction); 190 } 191 break; 192 } 193 default: { 194 break; 195 } 196 } 197 delete msg; 198 msg = nullptr; 199 } 200 } 201 Attach(sptr<OnTextChangedListener> & listener)202 void InputMethodController::Attach(sptr<OnTextChangedListener> &listener) 203 { 204 textListener = listener; 205 PrepareInput(0, mClient, mInputDataChannel, mAttribute); 206 StartInput(mClient); 207 } 208 ShowTextInput()209 void InputMethodController::ShowTextInput() 210 { 211 IMSA_HILOGI("InputMethodController::ShowTextInput"); 212 StartInput(mClient); 213 } 214 HideTextInput()215 void InputMethodController::HideTextInput() 216 { 217 IMSA_HILOGI("InputMethodController::HideTextInput"); 218 StopInput(mClient); 219 } 220 HideCurrentInput()221 void InputMethodController::HideCurrentInput() 222 { 223 IMSA_HILOGI("InputMethodController::HideCurrentInput"); 224 auto proxy = GetSystemAbilityProxy(); 225 if (proxy == nullptr) { 226 IMSA_HILOGE("proxy is nullptr"); 227 return; 228 } 229 MessageParcel data; 230 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()))) { 231 return; 232 } 233 proxy->HideCurrentInput(data); 234 } 235 Close()236 void InputMethodController::Close() 237 { 238 ReleaseInput(mClient); 239 textListener = nullptr; 240 } 241 PrepareInput(int32_t displayId,sptr<InputClientStub> & client,sptr<InputDataChannelStub> & channel,InputAttribute & attribute)242 void InputMethodController::PrepareInput(int32_t displayId, sptr<InputClientStub> &client, 243 sptr<InputDataChannelStub> &channel, InputAttribute &attribute) 244 { 245 IMSA_HILOGI("InputMethodController::PrepareInput"); 246 auto proxy = GetSystemAbilityProxy(); 247 if (proxy == nullptr) { 248 IMSA_HILOGE("proxy is nullptr"); 249 return; 250 } 251 MessageParcel data; 252 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()) 253 && data.WriteInt32(displayId) 254 && data.WriteRemoteObject(client->AsObject()) 255 && data.WriteRemoteObject(channel->AsObject()) 256 && data.WriteParcelable(&attribute))) { 257 return; 258 } 259 proxy->prepareInput(data); 260 } 261 DisplayOptionalInputMethod()262 void InputMethodController::DisplayOptionalInputMethod() 263 { 264 IMSA_HILOGI("InputMethodController::DisplayOptionalInputMethod"); 265 auto proxy = GetSystemAbilityProxy(); 266 if (proxy == nullptr) { 267 IMSA_HILOGE("proxy is nullptr"); 268 return; 269 } 270 MessageParcel data; 271 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()))) { 272 return; 273 } 274 proxy->displayOptionalInputMethod(data); 275 } 276 ListInputMethod()277 std::vector<InputMethodProperty*> InputMethodController::ListInputMethod() 278 { 279 IMSA_HILOGI("InputMethodController::listInputMethod"); 280 std::vector<InputMethodProperty*> properties; 281 auto proxy = GetSystemAbilityProxy(); 282 if (proxy == nullptr) { 283 IMSA_HILOGE("proxy is nullptr"); 284 return {}; 285 } 286 proxy->listInputMethod(&properties); 287 return properties; 288 } 289 StartInput(sptr<InputClientStub> & client)290 void InputMethodController::StartInput(sptr<InputClientStub> &client) 291 { 292 IMSA_HILOGI("InputMethodController::StartInput"); 293 auto proxy = GetSystemAbilityProxy(); 294 if (proxy == nullptr) { 295 IMSA_HILOGE("proxy is nullptr"); 296 return; 297 } 298 MessageParcel data; 299 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()) 300 && data.WriteRemoteObject(client->AsObject()))) { 301 return; 302 } 303 proxy->startInput(data); 304 } 305 ReleaseInput(sptr<InputClientStub> & client)306 void InputMethodController::ReleaseInput(sptr<InputClientStub> &client) 307 { 308 IMSA_HILOGI("InputMethodController::ReleaseInput"); 309 auto proxy = GetSystemAbilityProxy(); 310 if (proxy == nullptr) { 311 IMSA_HILOGE("proxy is nullptr"); 312 return; 313 } 314 MessageParcel data; 315 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()) 316 && data.WriteRemoteObject(client->AsObject().GetRefPtr()))) { 317 return; 318 } 319 proxy->releaseInput(data); 320 } 321 StopInput(sptr<InputClientStub> & client)322 void InputMethodController::StopInput(sptr<InputClientStub> &client) 323 { 324 IMSA_HILOGI("InputMethodController::StopInput"); 325 auto proxy = GetSystemAbilityProxy(); 326 if (proxy == nullptr) { 327 IMSA_HILOGE("proxy is nullptr"); 328 return; 329 } 330 MessageParcel data; 331 if (!(data.WriteInterfaceToken(proxy->GetDescriptor()) 332 && data.WriteRemoteObject(client->AsObject().GetRefPtr()))) { 333 return; 334 } 335 proxy->stopInput(data); 336 } 337 OnRemoteSaDied(const wptr<IRemoteObject> & remote)338 void InputMethodController::OnRemoteSaDied(const wptr<IRemoteObject> &remote) 339 { 340 IMSA_HILOGE("input method service died"); 341 std::lock_guard<std::mutex> lock(abilityLock_); 342 systemAbility_ = nullptr; 343 } 344 ImsaDeathRecipient()345 ImsaDeathRecipient::ImsaDeathRecipient() 346 { 347 } 348 OnRemoteDied(const wptr<IRemoteObject> & object)349 void ImsaDeathRecipient::OnRemoteDied(const wptr<IRemoteObject> &object) 350 { 351 InputMethodController::GetInstance()->OnRemoteSaDied(object); 352 } 353 OnCursorUpdate(CursorInfo cursorInfo)354 void InputMethodController::OnCursorUpdate(CursorInfo cursorInfo) 355 { 356 std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent(); 357 if (agent == nullptr) { 358 IMSA_HILOGI("InputMethodController::OnCursorUpdate agent is nullptr"); 359 return; 360 } 361 362 if (cursorInfo_.left == cursorInfo.left && cursorInfo_.top == cursorInfo.top 363 && cursorInfo_.height == cursorInfo.height) { 364 return; 365 } 366 cursorInfo_ = cursorInfo; 367 agent->OnCursorUpdate(cursorInfo.left, cursorInfo.top, cursorInfo.height); 368 } 369 OnSelectionChange(std::u16string text,int start,int end)370 void InputMethodController::OnSelectionChange(std::u16string text, int start, int end) 371 { 372 if (mTextString == text && mSelectNewBegin == start && mSelectNewEnd == end) { 373 return; 374 } 375 IMSA_HILOGI("InputMethodController::OnSelectionChange"); 376 mTextString = text; 377 mSelectOldBegin = mSelectNewBegin; 378 mSelectOldEnd = mSelectNewEnd; 379 mSelectNewBegin = start; 380 mSelectNewEnd = end; 381 std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent(); 382 if (agent == nullptr) { 383 IMSA_HILOGI("InputMethodController::OnSelectionChange agent is nullptr"); 384 return; 385 } 386 agent->OnSelectionChange(mTextString, mSelectOldBegin, mSelectOldEnd, mSelectNewBegin, mSelectNewEnd); 387 } 388 OnConfigurationChange(Configuration info)389 void InputMethodController::OnConfigurationChange(Configuration info) 390 { 391 IMSA_HILOGI("InputMethodController::OnConfigurationChange"); 392 enterKeyType_ = static_cast<uint32_t>(info.GetEnterKeyType()); 393 inputPattern_ = static_cast<uint32_t>(info.GetTextInputType()); 394 } 395 GetTextBeforeCursor(int32_t number)396 std::u16string InputMethodController::GetTextBeforeCursor(int32_t number) 397 { 398 IMSA_HILOGI("InputMethodController::GetTextBeforeCursor"); 399 if (!mTextString.empty()) { 400 int32_t startPos = (mSelectNewBegin >= number ? (mSelectNewBegin - number + 1) : 0); 401 return mTextString.substr(startPos, mSelectNewBegin); 402 } 403 return u""; 404 } 405 GetTextAfterCursor(int32_t number)406 std::u16string InputMethodController::GetTextAfterCursor(int32_t number) 407 { 408 IMSA_HILOGI("InputMethodController::GetTextBeforeCursor"); 409 if (!mTextString.empty()) { 410 int32_t endPos = (mSelectNewEnd+number<mTextString.size()) ? (mSelectNewEnd + number) : mTextString.size(); 411 return mTextString.substr(mSelectNewEnd, endPos); 412 } 413 return u""; 414 } 415 dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent)416 bool InputMethodController::dispatchKeyEvent(std::shared_ptr<MMI::KeyEvent> keyEvent) 417 { 418 IMSA_HILOGI("InputMethodController::dispatchKeyEvent"); 419 std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent(); 420 if (agent == nullptr) { 421 IMSA_HILOGI("InputMethodController::dispatchKeyEvent agent is nullptr"); 422 return false; 423 } 424 MessageParcel data; 425 if (!(data.WriteInterfaceToken(agent->GetDescriptor()) 426 && data.WriteInt32(keyEvent->GetKeyCode()) 427 && data.WriteInt32(keyEvent->GetKeyAction()))) { 428 return false; 429 } 430 431 return agent->DispatchKeyEvent(data); 432 } 433 GetEnterKeyType()434 int32_t InputMethodController::GetEnterKeyType() 435 { 436 IMSA_HILOGI("InputMethodController::GetEnterKeyType"); 437 return enterKeyType_; 438 } 439 GetInputPattern()440 int32_t InputMethodController::GetInputPattern() 441 { 442 IMSA_HILOGI("InputMethodController::GetInputPattern"); 443 return inputPattern_; 444 } 445 SetCallingWindow(uint32_t windowId)446 void InputMethodController::SetCallingWindow(uint32_t windowId) 447 { 448 IMSA_HILOGI("InputMethodController::SetCallingWindow windowId = %{public}d", windowId); 449 std::shared_ptr<IInputMethodAgent> agent = GetInputMethodAgent(); 450 if (agent == nullptr) { 451 IMSA_HILOGI("InputMethodController::SetCallingWindow agent is nullptr"); 452 return; 453 } 454 agent->SetCallingWindow(windowId); 455 return; 456 } 457 GetInputMethodAgent()458 std::shared_ptr<IInputMethodAgent> InputMethodController::GetInputMethodAgent() 459 { 460 std::lock_guard<std::mutex> lock(agentLock_); 461 return mAgent; 462 } 463 SetInputMethodAgent(sptr<IRemoteObject> & object)464 void InputMethodController::SetInputMethodAgent(sptr<IRemoteObject> &object) 465 { 466 IMSA_HILOGI("run in SetInputMethodAgent"); 467 std::lock_guard<std::mutex> lock(agentLock_); 468 std::shared_ptr<IInputMethodAgent> agent = std::make_shared<InputMethodAgentProxy>(object); 469 if (agent == nullptr) { 470 IMSA_HILOGI("InputMethodController::SetInputMethodAgent agent is nullptr"); 471 return; 472 } 473 mAgent = agent; 474 } 475 } // namespace MiscServices 476 } // namespace OHOS 477