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