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