• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2023 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 "imf_adapter_impl.h"
17 
18 #include "hisysevent_adapter.h"
19 #include "nweb_log.h"
20 #include "ohos_adapter_helper.h"
21 #include "cJSON.h"
22 
23 namespace OHOS::NWeb {
24 constexpr char INPUT_METHOD[] = "INPUT_METHOD";
25 constexpr char ATTACH_CODE[] = "ATTACH_CODE";
26 constexpr char IS_SHOW_KEY_BOARD[] = "IS_SHOW_KEY_BOARD";
27 constexpr int32_t IMF_LISTENER_NULL_POINT = 1;
28 constexpr int32_t IMF_TEXT_CONFIG_NULL_POINT = 2;
29 const std::string AUTO_FILL_CANCEL_PRIVATE_COMMAND = "autofill.cancel";
30 
IMFTextListenerAdapterImpl(const std::shared_ptr<IMFTextListenerAdapter> & listener)31 IMFTextListenerAdapterImpl::IMFTextListenerAdapterImpl(const std::shared_ptr<IMFTextListenerAdapter>& listener)
32     : listener_(listener) {};
33 
34 IMFTextListenerAdapterImpl::~IMFTextListenerAdapterImpl() = default;
35 
InsertText(const std::u16string & text)36 void IMFTextListenerAdapterImpl::InsertText(const std::u16string& text)
37 {
38     if (listener_) {
39         listener_->InsertText(text);
40     }
41 }
42 
DeleteForward(int32_t length)43 void IMFTextListenerAdapterImpl::DeleteForward(int32_t length)
44 {
45     if (listener_) {
46         listener_->DeleteForward(length);
47     }
48 }
49 
DeleteBackward(int32_t length)50 void IMFTextListenerAdapterImpl::DeleteBackward(int32_t length)
51 {
52     if (listener_) {
53         listener_->DeleteBackward(length);
54     }
55 }
56 
SendKeyEventFromInputMethod(const MiscServices::KeyEvent & event)57 void IMFTextListenerAdapterImpl::SendKeyEventFromInputMethod(const MiscServices::KeyEvent& event)
58 {
59     (void)event;
60     if (listener_) {
61         listener_->SendKeyEventFromInputMethod();
62     }
63 }
64 
SendKeyboardStatus(const MiscServices::KeyboardStatus & keyboardStatus)65 void IMFTextListenerAdapterImpl::SendKeyboardStatus(const MiscServices::KeyboardStatus& keyboardStatus)
66 {
67     if (listener_) {
68         auto status = IMFAdapterKeyboardStatus::NONE;
69         if (keyboardStatus == MiscServices::KeyboardStatus::SHOW) {
70             status = IMFAdapterKeyboardStatus::SHOW;
71         } else if (keyboardStatus == MiscServices::KeyboardStatus::HIDE) {
72             status = IMFAdapterKeyboardStatus::HIDE;
73         }
74         listener_->SendKeyboardStatus(status);
75     }
76 }
77 
SendFunctionKey(const MiscServices::FunctionKey & functionKey)78 void IMFTextListenerAdapterImpl::SendFunctionKey(const MiscServices::FunctionKey& functionKey)
79 {
80     if (listener_) {
81         std::shared_ptr<IMFAdapterFunctionKeyAdapterImpl> adapterFunction =
82             std::make_shared<IMFAdapterFunctionKeyAdapterImpl>();
83         switch (functionKey.GetEnterKeyType()) {
84             case MiscServices::EnterKeyType::UNSPECIFIED:
85                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::UNSPECIFIED);
86                 break;
87             case MiscServices::EnterKeyType::NONE:
88                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::NONE);
89                 break;
90             case MiscServices::EnterKeyType::GO:
91                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::GO);
92                 break;
93             case MiscServices::EnterKeyType::SEARCH:
94                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::SEARCH);
95                 break;
96             case MiscServices::EnterKeyType::SEND:
97                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::SEND);
98                 break;
99             case MiscServices::EnterKeyType::NEXT:
100                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::NEXT);
101                 break;
102             case MiscServices::EnterKeyType::DONE:
103                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::DONE);
104                 break;
105             case MiscServices::EnterKeyType::PREVIOUS:
106                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::PREVIOUS);
107                 break;
108             case MiscServices::EnterKeyType::NEW_LINE:
109                 adapterFunction->SetEnterKeyType(IMFAdapterEnterKeyType::NEW_LINE);
110                 break;
111             default:
112                 WVLOG_E("unknown functionKey");
113                 break;
114         }
115         listener_->SendFunctionKey(adapterFunction);
116     }
117 }
118 
SetKeyboardStatus(bool status)119 void IMFTextListenerAdapterImpl::SetKeyboardStatus(bool status)
120 {
121     if (listener_) {
122         listener_->SetKeyboardStatus(status);
123     }
124 }
125 
MoveCursor(const MiscServices::Direction direction)126 void IMFTextListenerAdapterImpl::MoveCursor(const MiscServices::Direction direction)
127 {
128     if (listener_) {
129         IMFAdapterDirection adapterDirection;
130         switch (direction) {
131             case MiscServices::Direction::UP: {
132                 adapterDirection = IMFAdapterDirection::UP;
133                 break;
134             }
135             case MiscServices::Direction::DOWN: {
136                 adapterDirection = IMFAdapterDirection::DOWN;
137                 break;
138             }
139             case MiscServices::Direction::LEFT: {
140                 adapterDirection = IMFAdapterDirection::LEFT;
141                 break;
142             }
143             case MiscServices::Direction::RIGHT: {
144                 adapterDirection = IMFAdapterDirection::RIGHT;
145                 break;
146             }
147             default: {
148                 adapterDirection = IMFAdapterDirection::NONE;
149             }
150         }
151         listener_->MoveCursor(adapterDirection);
152     }
153 }
154 
HandleSetSelection(int32_t start,int32_t end)155 void IMFTextListenerAdapterImpl::HandleSetSelection(int32_t start, int32_t end)
156 {
157     if (listener_) {
158         listener_->HandleSetSelection(start, end);
159     }
160 }
161 
HandleExtendAction(int32_t action)162 void IMFTextListenerAdapterImpl::HandleExtendAction(int32_t action)
163 {
164     if (listener_) {
165         listener_->HandleExtendAction(action);
166     }
167 }
168 
HandleSelect(int32_t keyCode,int32_t cursorMoveSkip)169 void IMFTextListenerAdapterImpl::HandleSelect(int32_t keyCode, int32_t cursorMoveSkip)
170 {
171     if (listener_) {
172         listener_->HandleSelect(keyCode, cursorMoveSkip);
173     }
174 }
175 
GetTextIndexAtCursor()176 int32_t IMFTextListenerAdapterImpl::GetTextIndexAtCursor()
177 {
178     if (listener_) {
179         return listener_->GetTextIndexAtCursor();
180     }
181     return -1;
182 }
183 
GetLeftTextOfCursor(int32_t number)184 std::u16string IMFTextListenerAdapterImpl::GetLeftTextOfCursor(int32_t number)
185 {
186     if (listener_) {
187         return listener_->GetLeftTextOfCursor(number);
188     }
189     return u"";
190 }
191 
GetRightTextOfCursor(int32_t number)192 std::u16string IMFTextListenerAdapterImpl::GetRightTextOfCursor(int32_t number)
193 {
194     if (listener_) {
195         return listener_->GetRightTextOfCursor(number);
196     }
197     return u"";
198 }
199 
SetPreviewText(const std::u16string & text,const MiscServices::Range & range)200 int32_t IMFTextListenerAdapterImpl::SetPreviewText(const std::u16string& text, const MiscServices::Range& range)
201 {
202     if (listener_) {
203         return listener_->SetPreviewText(text, range.start, range.end);
204     }
205     return -1;
206 }
207 
FinishTextPreview()208 void IMFTextListenerAdapterImpl::FinishTextPreview()
209 {
210     if (listener_) {
211         listener_->FinishTextPreview();
212     }
213 }
214 
ReceivePrivateCommand(const std::unordered_map<std::string,MiscServices::PrivateDataValue> & privateCommand)215 int32_t IMFTextListenerAdapterImpl::ReceivePrivateCommand(
216     const std::unordered_map<std::string, MiscServices::PrivateDataValue>& privateCommand)
217 {
218     WVLOG_I("ReceivePrivateCommand");
219     auto item = privateCommand.find(PREVIEW_TEXT_STYLE_KEY);
220     if (item != privateCommand.end()) {
221         bool isNeedUnderline = false;
222         MiscServices::PrivateDataValue data = item->second;
223         std::string previewStyle = std::get<std::string>(data);
224         if (previewStyle == PREVIEW_TEXT_STYLE_UNDERLINE) {
225             isNeedUnderline = true;
226         }
227 
228         if (listener_) {
229             listener_->SetNeedUnderLine(isNeedUnderline);
230         }
231     }
232 
233     item = privateCommand.find(AUTO_FILL_PARAMS_USERNAME);
234     if (item != privateCommand.end()) {
235         if (listener_) {
236             std::string content = std::get<std::string>(item->second);
237             listener_->AutoFillWithIMFEvent(true, false, false, content);
238         }
239     }
240 
241     item = privateCommand.find(AUTO_FILL_PARAMS_OTHERACCOUNT);
242     if (item != privateCommand.end()) {
243         if (listener_) {
244             std::string content = std::string("");
245             listener_->AutoFillWithIMFEvent(false, true, false, content);
246         }
247     }
248 
249     return 0;
250 }
251 
Attach(std::shared_ptr<IMFTextListenerAdapter> listener,bool isShowKeyboard)252 bool IMFAdapterImpl::Attach(std::shared_ptr<IMFTextListenerAdapter> listener, bool isShowKeyboard)
253 {
254     if (!listener) {
255         WVLOG_E("the listener is nullptr");
256         return false;
257     }
258     if (!textListener_) {
259         textListener_ = new (std::nothrow) IMFTextListenerAdapterImpl(listener);
260         if (!textListener_) {
261             WVLOG_E("new textListener failed");
262             return false;
263         }
264     }
265     int32_t ret = MiscServices::InputMethodController::GetInstance()->Attach(textListener_, isShowKeyboard);
266     if (ret != 0) {
267         WVLOG_E("inputmethod attach failed, errcode=%{public}d", ret);
268         return false;
269     }
270     return true;
271 }
272 
ReportImfErrorEvent(int32_t ret,bool isShowKeyboard)273 void ReportImfErrorEvent(int32_t ret, bool isShowKeyboard)
274 {
275     std::string isShowKeyboardStr = isShowKeyboard ? "true" : "false";
276     OhosAdapterHelper::GetInstance().GetHiSysEventAdapterInstance().Write(INPUT_METHOD,
277         HiSysEventAdapter::EventType::FAULT,
278         { ATTACH_CODE, std::to_string(ret), IS_SHOW_KEY_BOARD, isShowKeyboardStr });
279 }
280 
Attach(std::shared_ptr<IMFTextListenerAdapter> listener,bool isShowKeyboard,const std::shared_ptr<IMFTextConfigAdapter> config,bool isResetListener)281 bool IMFAdapterImpl::Attach(std::shared_ptr<IMFTextListenerAdapter> listener, bool isShowKeyboard,
282     const std::shared_ptr<IMFTextConfigAdapter> config, bool isResetListener)
283 {
284     if (!listener) {
285         WVLOG_E("the listener is nullptr");
286         ReportImfErrorEvent(IMF_LISTENER_NULL_POINT, isShowKeyboard);
287         return false;
288     }
289     if (!config || !(config->GetInputAttribute()) || !(config->GetCursorInfo())) {
290         WVLOG_E("the config is nullptr");
291         ReportImfErrorEvent(IMF_TEXT_CONFIG_NULL_POINT, isShowKeyboard);
292         return false;
293     }
294 
295     if ((textListener_ != nullptr) && isResetListener) {
296         textListener_ = nullptr;
297         WVLOG_I("attach node is changed, need reset listener");
298     }
299 
300     if (!textListener_) {
301         textListener_ = new (std::nothrow) IMFTextListenerAdapterImpl(listener);
302         if (!textListener_) {
303             WVLOG_E("new textListener failed");
304             ReportImfErrorEvent(IMF_LISTENER_NULL_POINT, isShowKeyboard);
305             return false;
306         }
307     }
308     MiscServices::InputAttribute inputAttribute = { .inputPattern = config->GetInputAttribute()->GetInputPattern(),
309         .enterKeyType = config->GetInputAttribute()->GetEnterKeyType(),
310         .isTextPreviewSupported = true };
311 
312     MiscServices::CursorInfo imfInfo = { .left = config->GetCursorInfo()->GetLeft(),
313         .top = config->GetCursorInfo()->GetTop(),
314         .width = config->GetCursorInfo()->GetWidth(),
315         .height = config->GetCursorInfo()->GetHeight() };
316 
317     MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
318         .cursorInfo = imfInfo,
319         .windowId = config->GetWindowId(),
320         .positionY = config->GetPositionY(),
321         .height = config->GetHeight() };
322     WVLOG_I(
323         "web inputmethod attach, isShowKeyboard=%{public}d, textConfig=%{public}s",
324         isShowKeyboard,
325         textConfig.ToString().c_str());
326     int32_t ret = MiscServices::InputMethodController::GetInstance()->Attach(textListener_, isShowKeyboard, textConfig);
327     if (ret != 0) {
328         WVLOG_E("inputmethod attach failed, errcode=%{public}d", ret);
329         ReportImfErrorEvent(ret, isShowKeyboard);
330         return false;
331     }
332     return true;
333 }
334 
AttachWithRequestKeyboardReason(std::shared_ptr<IMFTextListenerAdapter> listener,bool isShowKeyboard,const std::shared_ptr<IMFTextConfigAdapter> config,bool isResetListener,int32_t requestKeyboardReason)335 bool IMFAdapterImpl::AttachWithRequestKeyboardReason(std::shared_ptr<IMFTextListenerAdapter> listener,
336     bool isShowKeyboard, const std::shared_ptr<IMFTextConfigAdapter> config, bool isResetListener,
337     int32_t requestKeyboardReason)
338 {
339     if (!AttachParamsCheck(listener, isShowKeyboard, config, isResetListener)) {
340         return false;
341     }
342 
343     MiscServices::InputAttribute inputAttribute = { .inputPattern = config->GetInputAttribute()->GetInputPattern(),
344         .enterKeyType = config->GetInputAttribute()->GetEnterKeyType(),
345         .isTextPreviewSupported = true };
346 
347     MiscServices::CursorInfo imfInfo = { .left = config->GetCursorInfo()->GetLeft(),
348         .top = config->GetCursorInfo()->GetTop(),
349         .width = config->GetCursorInfo()->GetWidth(),
350         .height = config->GetCursorInfo()->GetHeight() };
351 
352     MiscServices::TextConfig textConfig = { .inputAttribute = inputAttribute,
353         .cursorInfo = imfInfo,
354         .windowId = config->GetWindowId(),
355         .positionY = config->GetPositionY(),
356         .height = config->GetHeight() };
357     OHOS::MiscServices::AttachOptions attachOptions;
358     attachOptions.isShowKeyboard = isShowKeyboard;
359     attachOptions.requestKeyboardReason = static_cast<OHOS::MiscServices::RequestKeyboardReason>(requestKeyboardReason);
360     WVLOG_I(
361         "web inputmethod attach, isShowKeyboard=%{public}d, requestKeyboardReason=%{public}d, textConfig=%{public}s",
362         isShowKeyboard,
363         requestKeyboardReason,
364         textConfig.ToString().c_str());
365     int32_t ret = MiscServices::InputMethodController::GetInstance()->Attach(textListener_, attachOptions, textConfig);
366     if (ret != 0) {
367         WVLOG_E("inputmethod attach failed, errcode=%{public}d", ret);
368         ReportImfErrorEvent(ret, isShowKeyboard);
369         return false;
370     }
371     return true;
372 }
373 
ShowCurrentInput(const IMFAdapterTextInputType & inputType)374 void IMFAdapterImpl::ShowCurrentInput(const IMFAdapterTextInputType& inputType)
375 {
376     MiscServices::Configuration config;
377     if (inputType == IMFAdapterTextInputType::NUMBER) {
378         config.SetTextInputType(MiscServices::TextInputType::NUMBER);
379     } else {
380         config.SetTextInputType(MiscServices::TextInputType::TEXT);
381     }
382     MiscServices::InputMethodController::GetInstance()->OnConfigurationChange(config);
383     MiscServices::InputMethodController::GetInstance()->ShowCurrentInput();
384 }
385 
HideTextInput()386 void IMFAdapterImpl::HideTextInput()
387 {
388     MiscServices::InputMethodController::GetInstance()->HideTextInput();
389 }
390 
Close()391 void IMFAdapterImpl::Close()
392 {
393     MiscServices::InputMethodController::GetInstance()->Close();
394 }
395 
OnCursorUpdate(const std::shared_ptr<IMFCursorInfoAdapter> cursorInfo)396 void IMFAdapterImpl::OnCursorUpdate(const std::shared_ptr<IMFCursorInfoAdapter> cursorInfo)
397 {
398     if (!cursorInfo) {
399         WVLOG_E("inputmethod OnCursorUpdate cursorInfo is null");
400         return;
401     }
402 
403     MiscServices::CursorInfo imfInfo = { .left = cursorInfo->GetLeft(),
404         .top = cursorInfo->GetTop(),
405         .width = cursorInfo->GetWidth(),
406         .height = cursorInfo->GetHeight() };
407     WVLOG_D("imfInfo left = %{public}f, top = %{public}f, width = %{public}f, height = %{public}f", imfInfo.left,
408         imfInfo.top, imfInfo.width, imfInfo.height);
409     MiscServices::InputMethodController::GetInstance()->OnCursorUpdate(imfInfo);
410 }
411 
OnSelectionChange(std::u16string text,int start,int end)412 void IMFAdapterImpl::OnSelectionChange(std::u16string text, int start, int end)
413 {
414     MiscServices::InputMethodController::GetInstance()->OnSelectionChange(text, start, end);
415 }
416 
SendPrivateCommand(const std::string & commandKey,const std::string & commandValue)417 bool IMFAdapterImpl::SendPrivateCommand(const std::string& commandKey, const std::string& commandValue)
418 {
419     if (commandKey == AUTO_FILL_CANCEL_PRIVATE_COMMAND) {
420         std::unordered_map<std::string, MiscServices::PrivateDataValue> privateCommand;
421         ParseFillContentJsonValue(commandValue, privateCommand);
422         int32_t ret = MiscServices::InputMethodController::GetInstance()->SendPrivateCommand(privateCommand);
423         if (ret != 0) {
424             WVLOG_E("inputmethod SendPrivateCommand failed, errcode=%{public}d", ret);
425             return false;
426         }
427         WVLOG_I("inputmethod  SendPrivateCommand success");
428         return true;
429     }
430     return false;
431 }
432 
ParseFillContentJsonValue(const std::string & commandValue,std::unordered_map<std::string,std::variant<std::string,bool,int32_t>> & map)433 bool IMFAdapterImpl::ParseFillContentJsonValue(const std::string& commandValue,
434     std::unordered_map<std::string, std::variant<std::string, bool, int32_t>>& map)
435 {
436     cJSON* sourceJson = cJSON_Parse(commandValue.c_str());
437     if (sourceJson == nullptr || cJSON_IsNull(sourceJson)) {
438         cJSON_Delete(sourceJson);
439         return false;
440     }
441     if (cJSON_HasObjectItem(sourceJson, "userName")) {
442         cJSON* userName = cJSON_GetObjectItem(sourceJson, "userName");
443         if (userName != nullptr && cJSON_IsString(userName) && userName->valuestring != nullptr) {
444             map.insert(std::make_pair("userName", userName->valuestring));
445         }
446     }
447     if (cJSON_HasObjectItem(sourceJson, "hasAccount")) {
448         cJSON* hasAccount = cJSON_GetObjectItem(sourceJson, "hasAccount");
449         if (hasAccount != nullptr && cJSON_IsString(hasAccount) && hasAccount->valuestring != nullptr) {
450             map.insert(std::make_pair("hasAccount", hasAccount->valuestring));
451         }
452     }
453     cJSON_Delete(sourceJson);
454     return true;
455 }
456 
AttachParamsCheck(std::shared_ptr<IMFTextListenerAdapter> listener,bool isShowKeyboard,const std::shared_ptr<IMFTextConfigAdapter> config,bool isResetListener)457 bool IMFAdapterImpl::AttachParamsCheck(std::shared_ptr<IMFTextListenerAdapter> listener, bool isShowKeyboard,
458     const std::shared_ptr<IMFTextConfigAdapter> config, bool isResetListener)
459 {
460     if (!listener) {
461         WVLOG_E("the listener is nullptr");
462         ReportImfErrorEvent(IMF_LISTENER_NULL_POINT, isShowKeyboard);
463         return false;
464     }
465     if (!config || !(config->GetInputAttribute()) || !(config->GetCursorInfo())) {
466         WVLOG_E("the config is nullptr");
467         ReportImfErrorEvent(IMF_TEXT_CONFIG_NULL_POINT, isShowKeyboard);
468         return false;
469     }
470 
471     if ((textListener_ != nullptr) && isResetListener) {
472         textListener_ = nullptr;
473         WVLOG_I("attach node is changed, need reset listener");
474     }
475 
476     if (!textListener_) {
477         textListener_ = new (std::nothrow) IMFTextListenerAdapterImpl(listener);
478         if (!textListener_) {
479             WVLOG_E("new textListener failed");
480             ReportImfErrorEvent(IMF_LISTENER_NULL_POINT, isShowKeyboard);
481             return false;
482         }
483     }
484     return true;
485 }
486 
NotifyPanelStatusInfo(const MiscServices::PanelStatusInfo & info)487 void IMFTextListenerAdapterImpl::NotifyPanelStatusInfo(const MiscServices::PanelStatusInfo& info)
488 {
489     MiscServices::Trigger triggerFrom = info.trigger;
490     if (listener_ && (triggerFrom == MiscServices::Trigger::IME_APP)) {
491         WVLOG_I("IMFTextListenerAdapterImpl::NotifyPanelStatusInfo, info.IME_APP");
492         listener_->KeyboardUpperRightCornerHide();
493     }
494 }
495 } // namespace OHOS::NWeb
496