1 /*
2  * Copyright (c) 2024 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 <string>
17 #include <locale>
18 #include <codecvt>
19 
20 #include "cj_input_method_controller.h"
21 #include "cj_input_method_textchanged_listener.h"
22 #include "cj_lambda.h"
23 #include "utils.h"
24 #include "input_method_utils.h"
25 #include "string_ex.h"
26 
27 namespace OHOS {
28 namespace MiscServices {
29 std::mutex CjInputMethodController::controllerMutex_;
30 std::shared_ptr<CjInputMethodController> CjInputMethodController::controller_{ nullptr };
31 const int8_t INSERT_TEXT = 0;
32 const int8_t DELETE_LEFT = 1;
33 const int8_t DELETE_RIGHT = 2;
34 const int8_t SEND_KEYBOARD_STATUS = 3;
35 const int8_t SEND_FUNCTION_KEY = 4;
36 const int8_t MOVE_CURSOR = 5;
37 const int8_t HANDLE_EXTEND_ACTION = 6;
38 const int8_t GET_LEFT_TEXT = 7;
39 const int8_t GET_RIGHT_TEXT = 8;
40 const int8_t GET_TEXT_INDEX = 9;
41 const int8_t SELECT_BY_MOVEMENT = 10;
42 const int8_t SELECT_BY_RANGE = 11;
43 
GetInstance()44 std::shared_ptr<CjInputMethodController> CjInputMethodController::GetInstance()
45 {
46     if (controller_ == nullptr) {
47         std::lock_guard<std::mutex> lock(controllerMutex_);
48         if (controller_ == nullptr) {
49             auto controller = std::make_shared<CjInputMethodController>();
50             controller_ = controller;
51             InputMethodController::GetInstance()->SetControllerListener(controller_);
52         }
53     }
54     return controller_;
55 }
56 
Attach(const CTextConfig &txtCfg, bool showKeyboard)57 int32_t CjInputMethodController::Attach(const CTextConfig &txtCfg, bool showKeyboard)
58 {
59     auto textListener = CjInputMethodTextChangedListener::GetInstance();
60     if (textListener == nullptr) {
61         IMSA_HILOGE("failed to create CjInputMethodTextChangedListener!");
62         return ERR_NO_MEMORY;
63     }
64     TextConfig textCfg = {
65         .inputAttribute = {
66             .inputPattern = txtCfg.inputAttrbute.textInputType,
67             .enterKeyType = txtCfg.inputAttrbute.enterKeyType
68         },
69         .cursorInfo = {
70             .left = txtCfg.cursor.left,
71             .top = txtCfg.cursor.top,
72             .width = txtCfg.cursor.width,
73             .height = txtCfg.cursor.height
74         },
75         .range = {
76             .start = txtCfg.range.start,
77             .end = txtCfg.range.end
78         },
79         .windowId = txtCfg.windowId
80     };
81 
82     auto controller = InputMethodController::GetInstance();
83     if (controller == nullptr) {
84         return ERR_NO_MEMORY;
85     }
86     return controller->Attach(textListener, showKeyboard, textCfg);
87 }
88 
Detach()89 int32_t CjInputMethodController::Detach()
90 {
91     auto controller = InputMethodController::GetInstance();
92     if (controller == nullptr) {
93         return ERR_NO_MEMORY;
94     }
95     return controller->Close();
96 }
97 
ShowTextInput()98 int32_t CjInputMethodController::ShowTextInput()
99 {
100     auto controller = InputMethodController::GetInstance();
101     if (controller == nullptr) {
102         return ERR_NO_MEMORY;
103     }
104     return controller->ShowTextInput();
105 }
106 
HideTextInput()107 int32_t CjInputMethodController::HideTextInput()
108 {
109     auto controller = InputMethodController::GetInstance();
110     if (controller == nullptr) {
111         return ERR_NO_MEMORY;
112     }
113     return controller->HideTextInput();
114 }
115 
SetCallingWindow(uint32_t windowId)116 int32_t CjInputMethodController::SetCallingWindow(uint32_t windowId)
117 {
118     auto controller = InputMethodController::GetInstance();
119     if (controller == nullptr) {
120         return ERR_NO_MEMORY;
121     }
122     return controller->SetCallingWindow(windowId);
123 }
124 
UpdateCursor(const CCursorInfo &cursor)125 int32_t CjInputMethodController::UpdateCursor(const CCursorInfo &cursor)
126 {
127     auto controller = InputMethodController::GetInstance();
128     if (controller == nullptr) {
129         return ERR_NO_MEMORY;
130     }
131     CursorInfo cursorInfo = {
132         .left = cursor.left,
133         .top = cursor.top,
134         .width = cursor.width,
135         .height = cursor.height
136     };
137     return controller->OnCursorUpdate(cursorInfo);
138 }
139 
ChangeSelection(const std::string &text, int32_t start, int32_t end)140 int32_t CjInputMethodController::ChangeSelection(const std::string &text, int32_t start, int32_t end)
141 {
142     auto controller = InputMethodController::GetInstance();
143     if (controller == nullptr) {
144         return ERR_NO_MEMORY;
145     }
146     std::wstring_convert<std::codecvt_utf8_utf16<char16_t>, char16_t> converter;
147     std::u16string txt = converter.from_bytes(text);
148     return controller->OnSelectionChange(txt, start, end);
149 }
150 
UpdateAttribute(const CInputAttribute &inputAttribute)151 int32_t CjInputMethodController::UpdateAttribute(const CInputAttribute &inputAttribute)
152 {
153     auto controller = InputMethodController::GetInstance();
154     if (controller == nullptr) {
155         return ERR_NO_MEMORY;
156     }
157     Configuration config = Configuration();
158     config.SetTextInputType(static_cast<TextInputType>(inputAttribute.textInputType));
159     config.SetEnterKeyType(static_cast<EnterKeyType>(inputAttribute.enterKeyType));
160     return controller->OnConfigurationChange(config);
161 }
162 
ShowSoftKeyboard()163 int32_t CjInputMethodController::ShowSoftKeyboard()
164 {
165     auto controller = InputMethodController::GetInstance();
166     if (controller == nullptr) {
167         return ERR_NO_MEMORY;
168     }
169     return controller->ShowSoftKeyboard();
170 }
171 
HideSoftKeyboard()172 int32_t CjInputMethodController::HideSoftKeyboard()
173 {
174     auto controller = InputMethodController::GetInstance();
175     if (controller == nullptr) {
176         return ERR_NO_MEMORY;
177     }
178     return controller->HideSoftKeyboard();
179 }
180 
StopInputSession()181 int32_t CjInputMethodController::StopInputSession()
182 {
183     auto controller = InputMethodController::GetInstance();
184     if (controller == nullptr) {
185         return ERR_NO_MEMORY;
186     }
187     return controller->StopInputSession();
188 }
189 
RegisterListener(int8_t type, int64_t id)190 void CjInputMethodController::RegisterListener(int8_t type, int64_t id)
191 {
192     std::lock_guard<std::recursive_mutex> lock(mutex_);
193     switch (type) {
194         case INSERT_TEXT:
195             InitInsertText(id);
196             break;
197         case DELETE_LEFT:
198             InitDeleteRight(id);
199             break;
200         case DELETE_RIGHT:
201             InitDeleteLeft(id);
202             break;
203         case SEND_KEYBOARD_STATUS:
204             InitSendKeyboardStatus(id);
205             break;
206         case SEND_FUNCTION_KEY:
207             InitSendFunctionKey(id);
208             break;
209         case MOVE_CURSOR:
210             InitMoveCursor(id);
211             break;
212         case HANDLE_EXTEND_ACTION:
213             InitHandleExtendAction(id);
214             break;
215         case GET_LEFT_TEXT:
216             InitGetLeftText(id);
217             break;
218         case GET_RIGHT_TEXT:
219             InitGetRightText(id);
220             break;
221         case GET_TEXT_INDEX:
222             InitGetTextIndexAtCursor(id);
223             break;
224         case SELECT_BY_MOVEMENT:
225             InitSelectByMovement(id);
226             break;
227         case SELECT_BY_RANGE:
228             InitSelectByRange(id);
229             break;
230         default:
231             return;
232     }
233 }
234 
UnRegisterListener(int8_t type)235 void CjInputMethodController::UnRegisterListener(int8_t type)
236 {
237     std::lock_guard<std::recursive_mutex> lock(mutex_);
238     switch (type) {
239         case INSERT_TEXT:
240             insertText = nullptr;
241             break;
242         case DELETE_LEFT:
243             deleteLeft = nullptr;
244             break;
245         case DELETE_RIGHT:
246             deleteRight = nullptr;
247             break;
248         case SEND_KEYBOARD_STATUS:
249             sendKeyboardStatus = nullptr;
250             break;
251         case SEND_FUNCTION_KEY:
252             sendFunctionKey = nullptr;
253             break;
254         case MOVE_CURSOR:
255             moveCursor = nullptr;
256             break;
257         case HANDLE_EXTEND_ACTION:
258             handleExtendAction = nullptr;
259             break;
260         case GET_LEFT_TEXT:
261             getLeftText = nullptr;
262             break;
263         case GET_RIGHT_TEXT:
264             getRightText = nullptr;
265             break;
266         case GET_TEXT_INDEX:
267             getTextIndexAtCursor = nullptr;
268             break;
269         case SELECT_BY_MOVEMENT:
270             onSelectByMovement = nullptr;
271             break;
272         case SELECT_BY_RANGE:
273             onSelectByRange = nullptr;
274             break;
275         default:
276             return;
277     }
278 }
279 
Subscribe(int8_t type, int64_t id)280 int32_t CjInputMethodController::Subscribe(int8_t type, int64_t id)
281 {
282     auto controller = CjInputMethodController::GetInstance();
283     if (controller == nullptr) {
284         return ERR_NO_MEMORY;
285     }
286     controller->RegisterListener(type, id);
287     return SUCCESS_CODE;
288 }
289 
Unsubscribe(int8_t type)290 int32_t CjInputMethodController::Unsubscribe(int8_t type)
291 {
292     auto controller = CjInputMethodController::GetInstance();
293     if (controller == nullptr) {
294         return ERR_NO_MEMORY;
295     }
296     controller->UnRegisterListener(type);
297     return SUCCESS_CODE;
298 }
299 
OnSelectByRange(int32_t start, int32_t end)300 void CjInputMethodController::OnSelectByRange(int32_t start, int32_t end)
301 {
302     if (onSelectByRange == nullptr) {
303         IMSA_HILOGD("onSelelctByRange null");
304         return;
305     }
306     IMSA_HILOGD("onSelelctByRange runs");
307     Range range = { .start = start, .end = end };
308     return onSelectByRange(range);
309 }
310 
OnSelectByMovement(int32_t direction)311 void CjInputMethodController::OnSelectByMovement(int32_t direction)
312 {
313     if (onSelectByMovement == nullptr) {
314         IMSA_HILOGD("onSelectByMovement null");
315         return;
316     }
317     IMSA_HILOGD("onSelectByMovement runs");
318     return onSelectByMovement(direction);
319 }
320 
InsertText(const std::u16string &text)321 void CjInputMethodController::InsertText(const std::u16string &text)
322 {
323     char *insertTxt = Utils::MallocCString(Str16ToStr8(text));
324     if (insertTxt == nullptr) {
325         IMSA_HILOGE("Failed to excute InsertText callback: out of memory.");
326         return;
327     }
328     if (insertText == nullptr) {
329         IMSA_HILOGD("insertText null");
330         free(insertTxt);
331         return;
332     }
333     IMSA_HILOGD("insertText runs");
334     insertText(insertTxt);
335     free(insertTxt);
336     return;
337 }
338 
DeleteRight(int32_t length)339 void CjInputMethodController::DeleteRight(int32_t length)
340 {
341     if (deleteRight == nullptr) {
342         IMSA_HILOGD("deleteRight null");
343         return;
344     }
345     IMSA_HILOGD("deleteRight runs");
346     deleteRight(length);
347     return;
348 }
349 
DeleteLeft(int32_t length)350 void CjInputMethodController::DeleteLeft(int32_t length)
351 {
352     if (deleteLeft == nullptr) {
353         IMSA_HILOGD("deleteLeft null");
354         return;
355     }
356     IMSA_HILOGD("deleteLeft runs");
357     deleteLeft(length);
358     return;
359 }
360 
SendKeyboardStatus(const KeyboardStatus &status)361 void CjInputMethodController::SendKeyboardStatus(const KeyboardStatus &status)
362 {
363     if (sendKeyboardStatus == nullptr) {
364         IMSA_HILOGD("sendKeyboardStatus null");
365         return;
366     }
367     IMSA_HILOGD("sendKeyboardStatus runs");
368     auto statusNum = static_cast<int32_t>(status);
369     sendKeyboardStatus(statusNum);
370     return;
371 }
372 
SendFunctionKey(const FunctionKey &functionKey)373 void CjInputMethodController::SendFunctionKey(const FunctionKey &functionKey)
374 {
375     if (sendFunctionKey == nullptr) {
376         IMSA_HILOGD("sendFunctionKey null");
377         return;
378     }
379     IMSA_HILOGD("sendFunctionKey runs");
380     auto type = static_cast<int32_t>(functionKey.GetEnterKeyType());
381     sendFunctionKey(type);
382     return;
383 }
384 
MoveCursor(const Direction direction)385 void CjInputMethodController::MoveCursor(const Direction direction)
386 {
387     if (moveCursor == nullptr) {
388         IMSA_HILOGD("moveCursor null");
389         return;
390     }
391     IMSA_HILOGD("moveCursor runs");
392     auto dir = static_cast<int32_t>(direction);
393     moveCursor(dir);
394     return;
395 }
396 
HandleExtendAction(int32_t action)397 void CjInputMethodController::HandleExtendAction(int32_t action)
398 {
399     if (handleExtendAction == nullptr) {
400         IMSA_HILOGD("handleExtendAction null");
401         return;
402     }
403     IMSA_HILOGD("handleExtendAction runs");
404     handleExtendAction(action);
405     return;
406 }
407 
GetLeftText(int32_t number)408 std::u16string CjInputMethodController::GetLeftText(int32_t number)
409 {
410     if (getLeftText == nullptr) {
411         IMSA_HILOGD("getLeftText null");
412         return u"";
413     }
414     IMSA_HILOGD("getLeftText runs");
415     char *text = getLeftText(number);
416     auto ret = Str8ToStr16(std::string(text));
417     free(text);
418     return ret;
419 }
420 
GetRightText(int32_t number)421 std::u16string CjInputMethodController::GetRightText(int32_t number)
422 {
423     if (getRightText == nullptr) {
424         IMSA_HILOGD("getRightText null");
425         return u"";
426     }
427     IMSA_HILOGD("getRightText runs");
428     char *text = getRightText(number);
429     auto ret = Str8ToStr16(std::string(text));
430     free(text);
431     return ret;
432 }
433 
GetTextIndexAtCursor()434 int32_t CjInputMethodController::GetTextIndexAtCursor()
435 {
436     if (getTextIndexAtCursor == nullptr) {
437         IMSA_HILOGD("getTextIndexAtCursor null");
438         return -1;
439     }
440     IMSA_HILOGD("getTextIndexAtCursor runs");
441     return getTextIndexAtCursor();
442 }
443 
InitInsertText(int64_t id)444 void CjInputMethodController::InitInsertText(int64_t id)
445 {
446     auto callback = reinterpret_cast<void(*)(const char*)>(id);
447     insertText = [lambda = CJLambda::Create(callback)](const char* text) -> void {
448         lambda(text);
449     };
450 }
451 
InitDeleteRight(int64_t id)452 void CjInputMethodController::InitDeleteRight(int64_t id)
453 {
454     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
455     deleteLeft = [lambda = CJLambda::Create(callback)](int32_t length) -> void {
456         lambda(length);
457     };
458 }
459 
InitDeleteLeft(int64_t id)460 void CjInputMethodController::InitDeleteLeft(int64_t id)
461 {
462     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
463     deleteRight = [lambda = CJLambda::Create(callback)](int32_t length) -> void {
464         lambda(length);
465     };
466 }
467 
InitSendKeyboardStatus(int64_t id)468 void CjInputMethodController::InitSendKeyboardStatus(int64_t id)
469 {
470     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
471     sendKeyboardStatus = [lambda = CJLambda::Create(callback)](int32_t status) -> void {
472         lambda(status);
473     };
474 }
475 
InitSendFunctionKey(int64_t id)476 void CjInputMethodController::InitSendFunctionKey(int64_t id)
477 {
478     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
479     sendFunctionKey = [lambda = CJLambda::Create(callback)](int32_t functionKey) -> void {
480         lambda(functionKey);
481     };
482 }
483 
InitMoveCursor(int64_t id)484 void CjInputMethodController::InitMoveCursor(int64_t id)
485 {
486     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
487     moveCursor = [lambda = CJLambda::Create(callback)](int32_t direction) -> void {
488         lambda(direction);
489     };
490 }
491 
InitHandleExtendAction(int64_t id)492 void CjInputMethodController::InitHandleExtendAction(int64_t id)
493 {
494     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
495     handleExtendAction = [lambda = CJLambda::Create(callback)](int32_t action) -> void {
496         lambda(action);
497     };
498 }
499 
InitGetLeftText(int64_t id)500 void CjInputMethodController::InitGetLeftText(int64_t id)
501 {
502     auto callback = reinterpret_cast<char*(*)(int32_t)>(id);
503     getLeftText = [lambda = CJLambda::Create(callback)](int32_t number) -> char* {
504         return lambda(number);
505     };
506 }
507 
InitGetRightText(int64_t id)508 void CjInputMethodController::InitGetRightText(int64_t id)
509 {
510     auto callback = reinterpret_cast<char*(*)(int32_t)>(id);
511     getRightText = [lambda = CJLambda::Create(callback)](int32_t number) -> char* {
512         return lambda(number);
513     };
514 }
515 
InitGetTextIndexAtCursor(int64_t id)516 void CjInputMethodController::InitGetTextIndexAtCursor(int64_t id)
517 {
518     auto callback = reinterpret_cast<int32_t(*)()>(id);
519     getTextIndexAtCursor = [lambda = CJLambda::Create(callback)](void) -> int32_t {
520         return lambda();
521     };
522 }
523 
InitSelectByMovement(int64_t id)524 void CjInputMethodController::InitSelectByMovement(int64_t id)
525 {
526     auto callback = reinterpret_cast<void(*)(int32_t)>(id);
527     onSelectByMovement = [lambda = CJLambda::Create(callback)](int32_t direction) -> void {
528         lambda(direction);
529     };
530 }
531 
InitSelectByRange(int64_t id)532 void CjInputMethodController::InitSelectByRange(int64_t id)
533 {
534     auto callback = reinterpret_cast<void(*)(Range)>(id);
535     onSelectByRange = [lambda = CJLambda::Create(callback)](Range range) -> void {
536         lambda(range);
537     };
538 }
539 
540 } // namespace MiscServices
541 } // namespace OHOS
542