1 /*
2  * Copyright (c) 2022-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 "js_text_input_client_engine.h"
17 
18 #include "input_method_ability.h"
19 #include "inputmethod_trace.h"
20 #include "js_util.h"
21 #include "js_utils.h"
22 #include "napi/native_api.h"
23 #include "napi/native_node_api.h"
24 #include "string_ex.h"
25 #include "wm_common.h"
26 
27 namespace OHOS {
28 namespace MiscServices {
29 #define ASYNC_POST(env, ctx) asyncCall.Post((env), (ctx), taskQueue_, __FUNCTION__)
30 using namespace std::chrono;
31 thread_local napi_ref JsTextInputClientEngine::TICRef_ = nullptr;
32 const std::string JsTextInputClientEngine::TIC_CLASS_NAME = "TextInputClient";
33 constexpr int32_t MAX_WAIT_TIME = 5000;
34 constexpr int32_t MAX_WAIT_TIME_PRIVATE_COMMAND = 2000;
35 std::shared_ptr<AsyncCall::TaskQueue> JsTextInputClientEngine::taskQueue_ = std::make_shared<AsyncCall::TaskQueue>();
36 BlockQueue<PrivateCommandInfo> JsTextInputClientEngine::privateCommandQueue_{ MAX_WAIT_TIME_PRIVATE_COMMAND };
37 uint32_t JsTextInputClientEngine::traceId_{ 0 };
Init(napi_env env,napi_value info)38 napi_value JsTextInputClientEngine::Init(napi_env env, napi_value info)
39 {
40     IMSA_HILOGD("JsTextInputClientEngine init");
41     napi_property_descriptor properties[] = {
42         DECLARE_NAPI_FUNCTION("sendKeyFunction", SendKeyFunction),
43         DECLARE_NAPI_FUNCTION("deleteForward", DeleteForward),
44         DECLARE_NAPI_FUNCTION("deleteBackward", DeleteBackward),
45         DECLARE_NAPI_FUNCTION("insertText", InsertText),
46         DECLARE_NAPI_FUNCTION("getForward", GetForward),
47         DECLARE_NAPI_FUNCTION("getBackward", GetBackward),
48         DECLARE_NAPI_FUNCTION("getEditorAttribute", GetEditorAttribute),
49         DECLARE_NAPI_FUNCTION("getTextIndexAtCursor", GetTextIndexAtCursor),
50         DECLARE_NAPI_FUNCTION("moveCursor", MoveCursor),
51         DECLARE_NAPI_FUNCTION("selectByRange", SelectByRange),
52         DECLARE_NAPI_FUNCTION("selectByMovement", SelectByMovement),
53         DECLARE_NAPI_FUNCTION("sendExtendAction", SendExtendAction),
54         DECLARE_NAPI_FUNCTION("insertTextSync", InsertTextSync),
55         DECLARE_NAPI_FUNCTION("moveCursorSync", MoveCursorSync),
56         DECLARE_NAPI_FUNCTION("getEditorAttributeSync", GetEditorAttributeSync),
57         DECLARE_NAPI_FUNCTION("selectByRangeSync", SelectByRangeSync),
58         DECLARE_NAPI_FUNCTION("selectByMovementSync", SelectByMovementSync),
59         DECLARE_NAPI_FUNCTION("getTextIndexAtCursorSync", GetTextIndexAtCursorSync),
60         DECLARE_NAPI_FUNCTION("deleteForwardSync", DeleteForwardSync),
61         DECLARE_NAPI_FUNCTION("deleteBackwardSync", DeleteBackwardSync),
62         DECLARE_NAPI_FUNCTION("getForwardSync", GetForwardSync),
63         DECLARE_NAPI_FUNCTION("getBackwardSync", GetBackwardSync),
64         DECLARE_NAPI_FUNCTION("sendPrivateCommand", SendPrivateCommand),
65         DECLARE_NAPI_FUNCTION("getCallingWindowInfo", GetCallingWindowInfo),
66         DECLARE_NAPI_FUNCTION("setPreviewText", SetPreviewText),
67         DECLARE_NAPI_FUNCTION("setPreviewTextSync", SetPreviewTextSync),
68         DECLARE_NAPI_FUNCTION("finishTextPreview", FinishTextPreview),
69         DECLARE_NAPI_FUNCTION("finishTextPreviewSync", FinishTextPreviewSync)
70     };
71     napi_value cons = nullptr;
72     NAPI_CALL(env, napi_define_class(env, TIC_CLASS_NAME.c_str(), TIC_CLASS_NAME.size(), JsConstructor, nullptr,
73                        sizeof(properties) / sizeof(napi_property_descriptor), properties, &cons));
74     NAPI_CALL(env, napi_create_reference(env, cons, 1, &TICRef_));
75     NAPI_CALL(env, napi_set_named_property(env, info, TIC_CLASS_NAME.c_str(), cons));
76 
77     return info;
78 }
79 
MoveCursor(napi_env env,napi_callback_info info)80 napi_value JsTextInputClientEngine::MoveCursor(napi_env env, napi_callback_info info)
81 {
82     auto ctxt = std::make_shared<MoveCursorContext>();
83     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
84         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
85         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "direction type must be number!",
86             TYPE_NONE, napi_generic_failure);
87         auto status = JsUtils::GetValue(env, argv[0], ctxt->num);
88         // 1 means least param num.
89         PARAM_CHECK_RETURN(env, ctxt->num >= 0, "direction should be not less than 0!", TYPE_NONE,
90             napi_generic_failure);
91         return status;
92     };
93     auto exec = [ctxt](AsyncCall::Context *ctx) {
94         int32_t code = InputMethodAbility::GetInstance()->MoveCursor(ctxt->num);
95         if (code == ErrorCode::NO_ERROR) {
96             ctxt->status = napi_ok;
97             ctxt->SetState(ctxt->status);
98         } else {
99             ctxt->SetErrorCode(code);
100         }
101     };
102     ctxt->SetAction(std::move(input));
103     // 2 means JsAPI:moveCursor has 2 params at most.
104     AsyncCall asyncCall(env, info, ctxt, 2);
105     return ASYNC_POST(env, exec);
106 }
107 
MoveCursorSync(napi_env env,napi_callback_info info)108 napi_value JsTextInputClientEngine::MoveCursorSync(napi_env env, napi_callback_info info)
109 {
110     size_t argc = 1;
111     napi_value argv[1] = { nullptr };
112     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
113     int32_t direction = 0;
114     // 1 means least param num.
115     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
116     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "direction must be number!", TYPE_NUMBER,
117         HandleParamCheckFailure(env));
118     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], direction), "direction covert failed!", TYPE_NONE,
119         HandleParamCheckFailure(env));
120     PARAM_CHECK_RETURN(env, direction >= 0, "direction should be no less than 0!", TYPE_NONE,
121         HandleParamCheckFailure(env));
122     IMSA_HILOGD("moveCursor , direction: %{public}d", direction);
123     int32_t ret = InputMethodAbility::GetInstance()->MoveCursor(direction);
124     if (ret != ErrorCode::NO_ERROR) {
125         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to move cursor!", TYPE_NONE);
126     }
127     return JsUtil::Const::Null(env);
128 }
129 
JsConstructor(napi_env env,napi_callback_info info)130 napi_value JsTextInputClientEngine::JsConstructor(napi_env env, napi_callback_info info)
131 {
132     napi_value thisVar = nullptr;
133     NAPI_CALL(env, napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr));
134 
135     JsTextInputClientEngine *clientObject = new (std::nothrow) JsTextInputClientEngine();
136     if (clientObject == nullptr) {
137         IMSA_HILOGE("clientObject is nullptr!");
138         napi_value result = nullptr;
139         napi_get_null(env, &result);
140         return result;
141     }
142     auto finalize = [](napi_env env, void *data, void *hint) {
143         IMSA_HILOGD("finalize.");
144         auto *objInfo = reinterpret_cast<JsTextInputClientEngine *>(data);
145         if (objInfo != nullptr) {
146             delete objInfo;
147         }
148     };
149     napi_status status = napi_wrap(env, thisVar, clientObject, finalize, nullptr, nullptr);
150     if (status != napi_ok) {
151         IMSA_HILOGE("failed to wrap: %{public}d!", status);
152         delete clientObject;
153         return nullptr;
154     }
155     return thisVar;
156 }
157 
GetTextInputClientInstance(napi_env env)158 napi_value JsTextInputClientEngine::GetTextInputClientInstance(napi_env env)
159 {
160     napi_value instance = nullptr;
161     napi_value cons = nullptr;
162     if (napi_get_reference_value(env, TICRef_, &cons) != napi_ok) {
163         IMSA_HILOGE("failed to get reference value!");
164         return nullptr;
165     }
166     if (napi_new_instance(env, cons, 0, nullptr, &instance) != napi_ok) {
167         IMSA_HILOGE("failed to new instance!");
168         return nullptr;
169     }
170     return instance;
171 }
172 
GetResult(napi_env env,std::string & text)173 napi_value JsTextInputClientEngine::GetResult(napi_env env, std::string &text)
174 {
175     napi_value jsText = nullptr;
176     napi_create_string_utf8(env, text.c_str(), NAPI_AUTO_LENGTH, &jsText);
177     return jsText;
178 }
179 
GetSelectRange(napi_env env,napi_value argv,std::shared_ptr<SelectContext> ctxt)180 napi_status JsTextInputClientEngine::GetSelectRange(napi_env env, napi_value argv, std::shared_ptr<SelectContext> ctxt)
181 {
182     napi_status status = napi_generic_failure;
183     napi_value napiValue = nullptr;
184     status = napi_get_named_property(env, argv, "start", &napiValue);
185     PARAM_CHECK_RETURN(env, status == napi_ok, "start of range cannot empty and must be number.", TYPE_NONE, status);
186     status = JsUtils::GetValue(env, napiValue, ctxt->start);
187     CHECK_RETURN(status == napi_ok, "failed to get start value!", status);
188 
189     status = napi_get_named_property(env, argv, "end", &napiValue);
190     PARAM_CHECK_RETURN(env, status == napi_ok, "end of range cannot empty and must be number.", TYPE_NONE, status);
191     status = JsUtils::GetValue(env, napiValue, ctxt->end);
192     if (status != napi_ok) {
193         IMSA_HILOGE("failed to get end value!");
194     }
195     return status;
196 }
197 
GetSelectMovement(napi_env env,napi_value argv,std::shared_ptr<SelectContext> ctxt)198 napi_status JsTextInputClientEngine::GetSelectMovement(
199     napi_env env, napi_value argv, std::shared_ptr<SelectContext> ctxt)
200 {
201     napi_status status = napi_generic_failure;
202     napi_value napiValue = nullptr;
203     status = napi_get_named_property(env, argv, "direction", &napiValue);
204     PARAM_CHECK_RETURN(env, status == napi_ok, "direction must be exist!", TYPE_NONE, status);
205     status = JsUtils::GetValue(env, napiValue, ctxt->direction);
206     if (status != napi_ok) {
207         IMSA_HILOGE("failed to get direction value!");
208     }
209     PARAM_CHECK_RETURN(env, status == napi_ok, "direction type must be Direction!", TYPE_NONE, status);
210     return status;
211 }
212 
SendKeyFunction(napi_env env,napi_callback_info info)213 napi_value JsTextInputClientEngine::SendKeyFunction(napi_env env, napi_callback_info info)
214 {
215     auto ctxt = std::make_shared<SendKeyFunctionContext>();
216     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
217         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
218         napi_status ret = JsUtils::GetValue(env, argv[0], ctxt->action);
219         PARAM_CHECK_RETURN(env, ret == napi_ok, "action type must be number!", TYPE_NONE, napi_generic_failure);
220         return napi_ok;
221     };
222     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
223         napi_status status = napi_get_boolean(env, ctxt->isSendKeyFunction, result);
224         return status;
225     };
226     auto exec = [ctxt](AsyncCall::Context *ctx) {
227         int32_t code = InputMethodAbility::GetInstance()->SendFunctionKey(ctxt->action);
228         if (code == ErrorCode::NO_ERROR) {
229             ctxt->status = napi_ok;
230             ctxt->SetState(ctxt->status);
231             ctxt->isSendKeyFunction = true;
232         } else {
233             ctxt->SetErrorCode(code);
234         }
235     };
236     ctxt->SetAction(std::move(input), std::move(output));
237     // 2 means JsAPI:sendKeyFunction has 2 params at most.
238     AsyncCall asyncCall(env, info, ctxt, 2);
239     return ASYNC_POST(env, exec);
240 }
241 
SendPrivateCommand(napi_env env,napi_callback_info info)242 napi_value JsTextInputClientEngine::SendPrivateCommand(napi_env env, napi_callback_info info)
243 {
244     auto ctxt = std::make_shared<SendPrivateCommandContext>();
245     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
246         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
247         napi_status status = JsUtils::GetValue(env, argv[0], ctxt->privateCommand);
248         CHECK_RETURN(status == napi_ok,
249             "commandData covert failed, type must be Record<string, CommandDataType>", status);
250         PARAM_CHECK_RETURN(env, TextConfig::IsPrivateCommandValid(ctxt->privateCommand),
251             "commandData size limit 32KB, count limit 5.", TYPE_NONE, napi_generic_failure);
252         ctxt->info = { std::chrono::system_clock::now(), ctxt->privateCommand };
253         privateCommandQueue_.Push(ctxt->info);
254         return status;
255     };
256     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
257     auto exec = [ctxt](AsyncCall::Context *ctx) {
258         privateCommandQueue_.Wait(ctxt->info);
259         int32_t code = InputMethodAbility::GetInstance()->SendPrivateCommand(ctxt->privateCommand);
260         privateCommandQueue_.Pop();
261         if (code == ErrorCode::NO_ERROR) {
262             ctxt->status = napi_ok;
263             ctxt->SetState(ctxt->status);
264         } else {
265             ctxt->SetErrorCode(code);
266         }
267     };
268     ctxt->SetAction(std::move(input), std::move(output));
269     // 1 means JsAPI:SendPrivateCommand has 1 param at most.
270     AsyncCall asyncCall(env, info, ctxt, 1);
271     return ASYNC_POST(env, exec);
272 }
273 
DeleteForwardSync(napi_env env,napi_callback_info info)274 napi_value JsTextInputClientEngine::DeleteForwardSync(napi_env env, napi_callback_info info)
275 {
276     InputMethodSyncTrace tracer("JS_DeleteForwardSync", GenerateTraceId());
277     size_t argc = 1;
278     napi_value argv[1] = { nullptr };
279     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
280     int32_t length = 0;
281     // 1 means least param num.
282     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
283     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length must be number!", TYPE_NUMBER,
284         HandleParamCheckFailure(env));
285     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], length), "length covert failed", TYPE_NONE,
286         HandleParamCheckFailure(env));
287     PARAM_CHECK_RETURN(env, length >= 0, "length should not less than 0!", TYPE_NONE, HandleParamCheckFailure(env));
288     IMSA_HILOGD("delete forward, length: %{public}d.", length);
289     int32_t ret = InputMethodAbility::GetInstance()->DeleteForward(length);
290     if (ret != ErrorCode::NO_ERROR) {
291         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to delete forward", TYPE_NONE);
292     }
293     return JsUtil::Const::Null(env);
294 }
295 
DeleteForward(napi_env env,napi_callback_info info)296 napi_value JsTextInputClientEngine::DeleteForward(napi_env env, napi_callback_info info)
297 {
298     auto traceId = GenerateTraceId();
299     InputMethodSyncTrace tracer("JS_DeleteForward_Start", traceId);
300     auto ctxt = std::make_shared<DeleteForwardContext>();
301     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
302         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
303         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length type must be number!",
304             TYPE_NONE, napi_generic_failure);
305         auto status = JsUtils::GetValue(env, argv[0], ctxt->length);
306         PARAM_CHECK_RETURN(env, ctxt->length >= 0, "length should no less than 0!", TYPE_NONE, napi_generic_failure);
307         return status;
308     };
309     auto output = [ctxt, traceId](napi_env env, napi_value *result) -> napi_status {
310         InputMethodSyncTrace tracer("JS_DeleteForward_Complete", traceId);
311         napi_status status = napi_get_boolean(env, ctxt->isDeleteForward, result);
312         return status;
313     };
314     auto exec = [ctxt, traceId](AsyncCall::Context *ctx) {
315         InputMethodSyncTrace tracer("JS_DeleteForward_Exec", traceId);
316         int32_t code = InputMethodAbility::GetInstance()->DeleteForward(ctxt->length);
317         if (code == ErrorCode::NO_ERROR) {
318             ctxt->status = napi_ok;
319             ctxt->SetState(ctxt->status);
320             ctxt->isDeleteForward = true;
321         } else {
322             ctxt->SetErrorCode(code);
323         }
324     };
325     ctxt->SetAction(std::move(input), std::move(output));
326     // 2 means JsAPI:deleteForward has 2 params at most.
327     AsyncCall asyncCall(env, info, ctxt, 2);
328     return ASYNC_POST(env, exec);
329 }
330 
DeleteBackwardSync(napi_env env,napi_callback_info info)331 napi_value JsTextInputClientEngine::DeleteBackwardSync(napi_env env, napi_callback_info info)
332 {
333     size_t argc = 1;
334     napi_value argv[1] = { nullptr };
335     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
336     int32_t length = 0;
337     // 1 means least param num.
338     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
339     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length must be number!", TYPE_NUMBER,
340         HandleParamCheckFailure(env));
341     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], length), "length covert failed!", TYPE_NONE,
342         HandleParamCheckFailure(env));
343     PARAM_CHECK_RETURN(env, length >= 0, "length should no less than 0!", TYPE_NONE, HandleParamCheckFailure(env));
344     IMSA_HILOGD("delete backward, length: %{public}d.", length);
345     int32_t ret = InputMethodAbility::GetInstance()->DeleteBackward(length);
346     if (ret != ErrorCode::NO_ERROR) {
347         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to delete backward", TYPE_NONE);
348     }
349     return JsUtil::Const::Null(env);
350 }
351 
DeleteBackward(napi_env env,napi_callback_info info)352 napi_value JsTextInputClientEngine::DeleteBackward(napi_env env, napi_callback_info info)
353 {
354     auto ctxt = std::make_shared<DeleteBackwardContext>();
355     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
356         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
357         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "param length type must be number!",
358             TYPE_NONE, napi_generic_failure);
359         auto status = JsUtils::GetValue(env, argv[0], ctxt->length);
360         return status;
361     };
362     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
363         napi_status status = napi_get_boolean(env, ctxt->isDeleteBackward, result);
364         return status;
365     };
366     auto exec = [ctxt](AsyncCall::Context *ctx) {
367         int32_t code = InputMethodAbility::GetInstance()->DeleteBackward(ctxt->length);
368         if (code == ErrorCode::NO_ERROR) {
369             ctxt->status = napi_ok;
370             ctxt->SetState(ctxt->status);
371             ctxt->isDeleteBackward = true;
372         } else {
373             ctxt->SetErrorCode(code);
374         }
375     };
376     ctxt->SetAction(std::move(input), std::move(output));
377     // 2 means JsAPI:deleteBackward has 2 params at most.
378     AsyncCall asyncCall(env, info, ctxt, 2);
379     return ASYNC_POST(env, exec);
380 }
381 
InsertText(napi_env env,napi_callback_info info)382 napi_value JsTextInputClientEngine::InsertText(napi_env env, napi_callback_info info)
383 {
384     auto traceId = GenerateTraceId();
385     InputMethodSyncTrace tracer("JS_InsertText_Start", traceId);
386     auto ctxt = std::make_shared<InsertTextContext>();
387     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
388         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
389         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_string, "text type must be string",
390             TYPE_NONE, napi_generic_failure);
391         auto status = JsUtils::GetValue(env, argv[0], ctxt->text);
392         return status;
393     };
394     auto output = [ctxt, traceId](napi_env env, napi_value *result) -> napi_status {
395         InputMethodSyncTrace tracer("JS_InsertText_Complete", traceId);
396         napi_status status = napi_get_boolean(env, ctxt->isInsertText, result);
397         return status;
398     };
399     auto exec = [ctxt, traceId](AsyncCall::Context *ctx) {
400         InputMethodSyncTrace tracer("JS_InsertText_Exec", traceId);
401         int32_t code = InputMethodAbility::GetInstance()->InsertText(ctxt->text);
402         if (code == ErrorCode::NO_ERROR) {
403             ctxt->status = napi_ok;
404             ctxt->SetState(ctxt->status);
405             ctxt->isInsertText = true;
406         } else {
407             ctxt->SetErrorCode(code);
408         }
409     };
410     ctxt->SetAction(std::move(input), std::move(output));
411     // 2 means JsAPI:insertText has 2 params at most.
412     AsyncCall asyncCall(env, info, ctxt, 2);
413     return ASYNC_POST(env, exec);
414 }
415 
InsertTextSync(napi_env env,napi_callback_info info)416 napi_value JsTextInputClientEngine::InsertTextSync(napi_env env, napi_callback_info info)
417 {
418     InputMethodSyncTrace tracer("JS_InsertTextSync", GenerateTraceId());
419     size_t argc = 1;
420     napi_value argv[1] = { nullptr };
421     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
422     std::string text;
423     // 1 means least param num.
424     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
425     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_string, "text must be string!", TYPE_STRING,
426         HandleParamCheckFailure(env));
427     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], text), "text covert failed!", TYPE_NONE,
428         HandleParamCheckFailure(env));
429     IMSA_HILOGD("insert text, text: %{public}s.", text.c_str());
430     int32_t ret = InputMethodAbility::GetInstance()->InsertText(text);
431     if (ret != ErrorCode::NO_ERROR) {
432         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to insert text!", TYPE_NONE);
433     }
434     return JsUtil::Const::Null(env);
435 }
436 
GetForwardSync(napi_env env,napi_callback_info info)437 napi_value JsTextInputClientEngine::GetForwardSync(napi_env env, napi_callback_info info)
438 {
439     InputMethodSyncTrace tracer("JS_GetForwardSync", GenerateTraceId());
440     size_t argc = 1;
441     napi_value argv[1] = { nullptr };
442     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
443     int32_t length = 0;
444     // 1 means least param num.
445     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
446     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length must be string!", TYPE_NUMBER,
447         HandleParamCheckFailure(env));
448     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], length), "length covert failed!", TYPE_NONE,
449         HandleParamCheckFailure(env));
450     PARAM_CHECK_RETURN(env, length >= 0, "length should no less than 0!", TYPE_NONE, HandleParamCheckFailure(env));
451     IMSA_HILOGD("get forward, length: %{public}d.", length);
452     std::u16string text;
453     int32_t ret = InputMethodAbility::GetInstance()->GetTextBeforeCursor(length, text);
454     if (ret != ErrorCode::NO_ERROR) {
455         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to get forward!", TYPE_NONE);
456         return JsUtil::Const::Null(env);
457     }
458     napi_value result = nullptr;
459     auto status = JsUtils::GetValue(env, Str16ToStr8(text), result);
460     CHECK_RETURN(status == napi_ok, "GetValue failed", JsUtil::Const::Null(env));
461     return result;
462 }
463 
GetForward(napi_env env,napi_callback_info info)464 napi_value JsTextInputClientEngine::GetForward(napi_env env, napi_callback_info info)
465 {
466     auto traceId = GenerateTraceId();
467     InputMethodSyncTrace tracer("JS_GetForward_Start", traceId);
468     auto ctxt = std::make_shared<GetForwardContext>();
469     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
470         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
471         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length type must be number!",
472             TYPE_NONE, napi_generic_failure);
473         auto status = JsUtils::GetValue(env, argv[0], ctxt->length);
474         return status;
475     };
476     auto output = [ctxt, traceId](napi_env env, napi_value *result) -> napi_status {
477         InputMethodSyncTrace tracer("JS_GetForward_Complete", traceId);
478         napi_value data = GetResult(env, ctxt->text);
479         *result = data;
480         return napi_ok;
481     };
482     auto exec = [ctxt, traceId](AsyncCall::Context *ctx) {
483         InputMethodSyncTrace tracer("JS_GetForward_Exec", traceId);
484         std::u16string temp;
485         int32_t code = InputMethodAbility::GetInstance()->GetTextBeforeCursor(ctxt->length, temp);
486         if (code == ErrorCode::NO_ERROR) {
487             ctxt->status = napi_ok;
488             ctxt->SetState(ctxt->status);
489             ctxt->text = Str16ToStr8(temp);
490         } else {
491             ctxt->SetErrorCode(code);
492         }
493     };
494     ctxt->SetAction(std::move(input), std::move(output));
495     // 2 means JsAPI:getForward has 2 params at most.
496     AsyncCall asyncCall(env, info, ctxt, 2);
497     return ASYNC_POST(env, exec);
498 }
499 
GetBackwardSync(napi_env env,napi_callback_info info)500 napi_value JsTextInputClientEngine::GetBackwardSync(napi_env env, napi_callback_info info)
501 {
502     size_t argc = 1;
503     napi_value argv[1] = { nullptr };
504     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
505     int32_t length = 0;
506     // 1 means least param num.
507     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
508     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length must be string!", TYPE_NUMBER,
509         HandleParamCheckFailure(env));
510     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], length), "length covert failed!", TYPE_NONE,
511         HandleParamCheckFailure(env));
512     PARAM_CHECK_RETURN(env, length >= 0, "length should not less than 0!", TYPE_NONE, HandleParamCheckFailure(env));
513     IMSA_HILOGD("get backward, length: %{public}d.", length);
514     std::u16string text;
515     int32_t ret = InputMethodAbility::GetInstance()->GetTextAfterCursor(length, text);
516     if (ret != ErrorCode::NO_ERROR) {
517         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to get backward!", TYPE_NONE);
518         return JsUtil::Const::Null(env);
519     }
520     napi_value result = nullptr;
521     auto status = JsUtils::GetValue(env, Str16ToStr8(text), result);
522     CHECK_RETURN(status == napi_ok, "GetValue failed", JsUtil::Const::Null(env));
523     return result;
524 }
525 
GetBackward(napi_env env,napi_callback_info info)526 napi_value JsTextInputClientEngine::GetBackward(napi_env env, napi_callback_info info)
527 {
528     auto ctxt = std::make_shared<GetBackwardContext>();
529     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
530         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
531         PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_number, "length type must be number!",
532             TYPE_NONE, napi_generic_failure);
533         auto status = JsUtils::GetValue(env, argv[0], ctxt->length);
534         return status;
535     };
536     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
537         napi_value data = GetResult(env, ctxt->text);
538         *result = data;
539         return napi_ok;
540     };
541     auto exec = [ctxt](AsyncCall::Context *ctx) {
542         std::u16string temp;
543         int32_t code = InputMethodAbility::GetInstance()->GetTextAfterCursor(ctxt->length, temp);
544         if (code == ErrorCode::NO_ERROR) {
545             ctxt->status = napi_ok;
546             ctxt->SetState(ctxt->status);
547             ctxt->text = Str16ToStr8(temp);
548         } else {
549             ctxt->SetErrorCode(code);
550         }
551     };
552     ctxt->SetAction(std::move(input), std::move(output));
553     // 2 means JsAPI:getBackward has 2 params at most.
554     AsyncCall asyncCall(env, info, ctxt, 2);
555     return ASYNC_POST(env, exec);
556 }
557 
GetEditorAttributeSync(napi_env env,napi_callback_info info)558 napi_value JsTextInputClientEngine::GetEditorAttributeSync(napi_env env, napi_callback_info info)
559 {
560     TextTotalConfig config;
561     int32_t ret = InputMethodAbility::GetInstance()->GetTextConfig(config);
562     if (ret != ErrorCode::NO_ERROR) {
563         IMSA_HILOGE("failed to get text config: %{public}d!", ret);
564         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_IMCLIENT, "failed to get text config!", TYPE_NONE);
565     }
566     IMSA_HILOGD("inputPattern: %{public}d, enterKeyType: %{public}d, isTextPreviewSupported: %{public}d.",
567         config.inputAttribute.inputPattern, config.inputAttribute.enterKeyType,
568         config.inputAttribute.isTextPreviewSupported);
569     return JsInputAttribute::Write(env, config.inputAttribute);
570 }
571 
GetEditorAttribute(napi_env env,napi_callback_info info)572 napi_value JsTextInputClientEngine::GetEditorAttribute(napi_env env, napi_callback_info info)
573 {
574     auto ctxt = std::make_shared<GetEditorAttributeContext>();
575     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
576         *result = JsInputAttribute::Write(env, ctxt->inputAttribute);
577         return napi_ok;
578     };
579     auto exec = [ctxt](AsyncCall::Context *ctx) {
580         TextTotalConfig config;
581         int32_t ret = InputMethodAbility::GetInstance()->GetTextConfig(config);
582         ctxt->inputAttribute = config.inputAttribute;
583         if (ret == ErrorCode::NO_ERROR) {
584             ctxt->SetState(napi_ok);
585             IMSA_HILOGD("inputPattern: %{public}d, enterKeyType: %{public}d, isTextPreviewSupported: %{public}d",
586                 config.inputAttribute.inputPattern, config.inputAttribute.enterKeyType,
587                 config.inputAttribute.isTextPreviewSupported);
588         } else {
589             IMSA_HILOGE("failed to get text config: %{public}d!", ret);
590             ctxt->SetErrorCode(IMFErrorCode::EXCEPTION_IMCLIENT);
591             ctxt->SetErrorMessage("failed to get text config!");
592         }
593     };
594     ctxt->SetAction(nullptr, std::move(output));
595     // 1 means JsAPI:getEditorAttribute has 1 param at most.
596     AsyncCall asyncCall(env, info, ctxt, 1);
597     return ASYNC_POST(env, exec);
598 }
599 
SelectByRange(napi_env env,napi_callback_info info)600 napi_value JsTextInputClientEngine::SelectByRange(napi_env env, napi_callback_info info)
601 {
602     IMSA_HILOGD("run in");
603     auto ctxt = std::make_shared<SelectContext>();
604     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
605         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
606         napi_valuetype valueType = napi_undefined;
607         napi_typeof(env, argv[0], &valueType);
608         PARAM_CHECK_RETURN(env, valueType == napi_object, "range type must be Range!", TYPE_NONE,
609             napi_generic_failure);
610         auto status = GetSelectRange(env, argv[0], ctxt);
611         return status;
612     };
613     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
614     auto exec = [ctxt](AsyncCall::Context *ctx) {
615         int32_t code = InputMethodAbility::GetInstance()->SelectByRange(ctxt->start, ctxt->end);
616         if (code == ErrorCode::NO_ERROR) {
617             ctxt->status = napi_ok;
618             ctxt->SetState(ctxt->status);
619         } else {
620             ctxt->SetErrorCode(code);
621         }
622     };
623     ctxt->SetAction(std::move(input), std::move(output));
624     // 2 means JsAPI:selectByRange has 2 params at most.
625     AsyncCall asyncCall(env, info, ctxt, 2);
626     return ASYNC_POST(env, exec);
627 }
628 
SelectByRangeSync(napi_env env,napi_callback_info info)629 napi_value JsTextInputClientEngine::SelectByRangeSync(napi_env env, napi_callback_info info)
630 {
631     IMSA_HILOGD("SelectByRangeSync");
632     size_t argc = 1;
633     napi_value argv[1] = { nullptr };
634     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
635     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
636     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_object, "range type must be Range!", TYPE_NONE,
637         HandleParamCheckFailure(env));
638     auto ctxt = std::make_shared<SelectContext>();
639     auto status = GetSelectRange(env, argv[0], ctxt);
640     if (status != napi_ok) {
641         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK,
642             "failed to get start or end, should have start and end number!", TYPE_NONE);
643         return JsUtil::Const::Null(env);
644     }
645     IMSA_HILOGD("start: %{public}d, end: %{public}d.", ctxt->start, ctxt->end);
646     int32_t ret = InputMethodAbility::GetInstance()->SelectByRange(ctxt->start, ctxt->end);
647     if (ret != ErrorCode::NO_ERROR) {
648         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to select by range!", TYPE_NONE);
649     }
650     return JsUtil::Const::Null(env);
651 }
652 
SelectByMovementSync(napi_env env,napi_callback_info info)653 napi_value JsTextInputClientEngine::SelectByMovementSync(napi_env env, napi_callback_info info)
654 {
655     IMSA_HILOGD("run in");
656     size_t argc = 1;
657     napi_value argv[1] = { nullptr };
658     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
659     PARAM_CHECK_RETURN(env, argc >= 1, "at least one parameter is required!", TYPE_NONE, HandleParamCheckFailure(env));
660     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[0]) == napi_object, "movement type must be Movement!",
661         TYPE_NONE, HandleParamCheckFailure(env));
662     auto ctxt = std::make_shared<SelectContext>();
663     auto status = GetSelectMovement(env, argv[0], ctxt);
664     if (status != napi_ok) {
665         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK, "direction covert failed!", TYPE_NONE);
666         return JsUtil::Const::Null(env);
667     }
668     IMSA_HILOGD("direction: %{public}d.", ctxt->direction);
669     int32_t ret = InputMethodAbility::GetInstance()->SelectByMovement(ctxt->direction);
670     if (ret != ErrorCode::NO_ERROR) {
671         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to select by movement!", TYPE_NONE);
672     }
673     return JsUtil::Const::Null(env);
674 }
675 
SelectByMovement(napi_env env,napi_callback_info info)676 napi_value JsTextInputClientEngine::SelectByMovement(napi_env env, napi_callback_info info)
677 {
678     IMSA_HILOGD("run in");
679     auto ctxt = std::make_shared<SelectContext>();
680     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
681         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
682         napi_valuetype valueType = napi_undefined;
683         napi_typeof(env, argv[0], &valueType);
684         PARAM_CHECK_RETURN(env, valueType == napi_object, "movement type must be Movement!", TYPE_NONE,
685             napi_generic_failure);
686         auto status = GetSelectMovement(env, argv[0], ctxt);
687         return status;
688     };
689     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status { return napi_ok; };
690     auto exec = [ctxt](AsyncCall::Context *ctx) {
691         int32_t code = InputMethodAbility::GetInstance()->SelectByMovement(ctxt->direction);
692         if (code == ErrorCode::NO_ERROR) {
693             ctxt->status = napi_ok;
694             ctxt->SetState(ctxt->status);
695         } else {
696             ctxt->SetErrorCode(code);
697         }
698     };
699     ctxt->SetAction(std::move(input), std::move(output));
700     // 2 means JsAPI:selectByMovement has 2 params at most.
701     AsyncCall asyncCall(env, info, ctxt, 2);
702     return ASYNC_POST(env, exec);
703 }
704 
SendExtendAction(napi_env env,napi_callback_info info)705 napi_value JsTextInputClientEngine::SendExtendAction(napi_env env, napi_callback_info info)
706 {
707     auto ctxt = std::make_shared<SendExtendActionContext>();
708     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
709         PARAM_CHECK_RETURN(env, argc > 0, "at least one parameter is required!", TYPE_NONE, napi_generic_failure);
710         auto status = JsUtils::GetValue(env, argv[0], ctxt->action);
711         if (status != napi_ok) {
712             ctxt->SetErrorMessage("action must be number and should in ExtendAction");
713         }
714         return status;
715     };
716     auto exec = [ctxt](AsyncCall::Context *ctx) {
717         int32_t code = InputMethodAbility::GetInstance()->SendExtendAction(ctxt->action);
718         if (code == ErrorCode::NO_ERROR) {
719             ctxt->SetState(napi_ok);
720             return;
721         }
722         ctxt->SetErrorCode(code);
723     };
724     ctxt->SetAction(std::move(input));
725     // 2 means JsAPI:sendExtendAction has 2 params at most.
726     AsyncCall asyncCall(env, info, ctxt, 2);
727     return ASYNC_POST(env, exec);
728 }
729 
GetTextIndexAtCursor(napi_env env,napi_callback_info info)730 napi_value JsTextInputClientEngine::GetTextIndexAtCursor(napi_env env, napi_callback_info info)
731 {
732     IMSA_HILOGD("GetTextIndexAtCursor");
733     auto ctxt = std::make_shared<GetTextIndexAtCursorContext>();
734     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
735         return napi_ok;
736     };
737     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
738         return napi_create_int32(env, ctxt->index, result);
739     };
740     auto exec = [ctxt](AsyncCall::Context *ctx) {
741         int32_t code = InputMethodAbility::GetInstance()->GetTextIndexAtCursor(ctxt->index);
742         if (code == ErrorCode::NO_ERROR) {
743             ctxt->status = napi_ok;
744             ctxt->SetState(ctxt->status);
745         } else {
746             ctxt->SetErrorCode(code);
747         }
748     };
749     ctxt->SetAction(std::move(input), std::move(output));
750     // 1 means JsAPI:getTextIndexAtCursor has 1 param at most.
751     AsyncCall asyncCall(env, info, ctxt, 1);
752     return ASYNC_POST(env, exec);
753 }
754 
SetPreviewText(napi_env env,napi_callback_info info)755 napi_value JsTextInputClientEngine::SetPreviewText(napi_env env, napi_callback_info info)
756 {
757     auto traceId = GenerateTraceId();
758     InputMethodSyncTrace tracer("JS_SetPreviewText_Start", traceId);
759     IMSA_HILOGD("JsTextInputClientEngine in");
760     auto ctxt = std::make_shared<SetPreviewTextContext>();
761     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
762         if (GetPreviewTextParam(env, argc, argv, ctxt->text, ctxt->range) != napi_ok) {
763             return napi_generic_failure;
764         }
765         return napi_ok;
766     };
767     auto output = [ctxt, traceId](napi_env env, napi_value *result) -> napi_status {
768         InputMethodSyncTrace tracer("JS_SetPreviewText_Complete", traceId);
769         return napi_ok;
770     };
771     auto exec = [ctxt, traceId](AsyncCall::Context *ctx) {
772         InputMethodSyncTrace tracer("JS_SetPreviewText_Exec", traceId);
773         int32_t code = InputMethodAbility::GetInstance()->SetPreviewText(ctxt->text, ctxt->range);
774         if (code == ErrorCode::NO_ERROR) {
775             IMSA_HILOGD("exec setPreviewText success");
776             ctxt->SetState(napi_ok);
777         } else if (code == ErrorCode::ERROR_INVALID_RANGE) {
778             ctxt->SetErrorCode(code);
779             ctxt->SetErrorMessage("range should be included in preview text range, otherwise should be included in "
780                                   "total text range!");
781         } else {
782             ctxt->SetErrorCode(code);
783         }
784     };
785     ctxt->SetAction(std::move(input), std::move(output));
786     // 2 means JsAPI:setPreviewText needs 2 params at most
787     AsyncCall asyncCall(env, info, ctxt, 2);
788     return ASYNC_POST(env, exec);
789 }
790 
SetPreviewTextSync(napi_env env,napi_callback_info info)791 napi_value JsTextInputClientEngine::SetPreviewTextSync(napi_env env, napi_callback_info info)
792 {
793     InputMethodSyncTrace tracer("JS_SetPreviewTextSync", GenerateTraceId());
794     IMSA_HILOGD("start.");
795     // 2 means JsAPI:setPreviewText needs 2 params at most
796     size_t argc = 2;
797     napi_value argv[2] = { nullptr };
798     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, nullptr, nullptr));
799     std::string text;
800     Range range;
801     if (GetPreviewTextParam(env, argc, argv, text, range) != napi_ok) {
802         return JsUtil::Const::Null(env);
803     }
804     int32_t ret = InputMethodAbility::GetInstance()->SetPreviewText(text, range);
805     if (ret == ErrorCode::ERROR_INVALID_RANGE) {
806         JsUtils::ThrowException(env, IMFErrorCode::EXCEPTION_PARAMCHECK,
807             "range should be included in preview text range, otherwise should be included in total text range",
808             TYPE_NONE);
809     } else if (ret != ErrorCode::NO_ERROR) {
810         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to set preview text!", TYPE_NONE);
811     }
812     return JsUtil::Const::Null(env);
813 }
814 
FinishTextPreview(napi_env env,napi_callback_info info)815 napi_value JsTextInputClientEngine::FinishTextPreview(napi_env env, napi_callback_info info)
816 {
817     auto traceId = GenerateTraceId();
818     InputMethodSyncTrace tracer("JS_FinishTextPreview_Start", traceId);
819     IMSA_HILOGD("start.");
820     auto ctxt = std::make_shared<FinishTextPreviewContext>();
821     auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
822         return napi_ok;
823     };
824     auto output = [ctxt, traceId](napi_env env, napi_value *result) -> napi_status {
825         InputMethodSyncTrace tracer("JS_FinishTextPreview_Complete", traceId);
826         return napi_ok;
827     };
828     auto exec = [ctxt, traceId](AsyncCall::Context *ctx) {
829         InputMethodSyncTrace tracer("JS_FinishTextPreview_Exec", traceId);
830         int32_t code = InputMethodAbility::GetInstance()->FinishTextPreview(false);
831         if (code == ErrorCode::NO_ERROR) {
832             IMSA_HILOGI("exec finishTextPreview success.");
833             ctxt->SetState(napi_ok);
834         } else {
835             ctxt->SetErrorCode(code);
836         }
837     };
838     ctxt->SetAction(std::move(input), std::move(output));
839     // 0 means JsAPI:finishTextPreview needs no param
840     AsyncCall asyncCall(env, info, ctxt, 0);
841     return ASYNC_POST(env, exec);
842 }
843 
FinishTextPreviewSync(napi_env env,napi_callback_info info)844 napi_value JsTextInputClientEngine::FinishTextPreviewSync(napi_env env, napi_callback_info info)
845 {
846     InputMethodSyncTrace tracer("JS_FinishTextPreviewSync", GenerateTraceId());
847     IMSA_HILOGD("JsTextInputClientEngine in");
848     int32_t ret = InputMethodAbility::GetInstance()->FinishTextPreview(false);
849     if (ret != ErrorCode::NO_ERROR) {
850         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to finish text preview!", TYPE_NONE);
851     }
852     return JsUtil::Const::Null(env);
853 }
854 
GetTextIndexAtCursorSync(napi_env env,napi_callback_info info)855 napi_value JsTextInputClientEngine::GetTextIndexAtCursorSync(napi_env env, napi_callback_info info)
856 {
857     IMSA_HILOGD("start.");
858     int32_t index = 0;
859     int32_t ret = InputMethodAbility::GetInstance()->GetTextIndexAtCursor(index);
860     if (ret != ErrorCode::NO_ERROR) {
861         JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to get text index at cursor!", TYPE_NONE);
862     }
863     return JsUtil::GetValue(env, index);
864 }
865 
GetCallingWindowInfo(napi_env env,napi_callback_info info)866 napi_value JsTextInputClientEngine::GetCallingWindowInfo(napi_env env, napi_callback_info info)
867 {
868     IMSA_HILOGD("start.");
869     auto ctxt = std::make_shared<GetCallingWindowInfoContext>();
870     auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
871         *result = JsCallingWindowInfo::Write(env, ctxt->windowInfo);
872         return napi_ok;
873     };
874     auto exec = [ctxt](AsyncCall::Context *ctx) {
875         int32_t ret = InputMethodAbility::GetInstance()->GetCallingWindowInfo(ctxt->windowInfo);
876         if (ret == ErrorCode::NO_ERROR) {
877             IMSA_HILOGI("exec GetCallingWindowInfo success.");
878             ctxt->SetState(napi_ok);
879             return;
880         }
881         ctxt->SetErrorCode(ret);
882     };
883     ctxt->SetAction(nullptr, std::move(output));
884     // 0 means JsAPI:getCallingWindowInfo needs no parameter.
885     AsyncCall asyncCall(env, info, ctxt, 0);
886     return ASYNC_POST(env, exec);
887 }
888 
GetPreviewTextParam(napi_env env,size_t argc,napi_value * argv,std::string & text,Range & range)889 napi_status JsTextInputClientEngine::GetPreviewTextParam(
890     napi_env env, size_t argc, napi_value *argv, std::string &text, Range &range)
891 {
892     // 2 means JsAPI:setPreviewText needs 2 params at least.
893     PARAM_CHECK_RETURN(env, argc >= 2, "at least two parameters is required!", TYPE_NONE, napi_generic_failure);
894     PARAM_CHECK_RETURN(env, JsUtil::GetValue(env, argv[0], text), "text covert failed, must be string!",
895         TYPE_NONE, napi_generic_failure);
896     PARAM_CHECK_RETURN(env, JsUtil::GetType(env, argv[1]) == napi_object, "range type must be Range!", TYPE_NONE,
897         napi_generic_failure);
898     PARAM_CHECK_RETURN(env, JsRange::Read(env, argv[1], range),
899         "range covert failed, the range should have numbers start and end", TYPE_NONE, napi_generic_failure);
900     return napi_ok;
901 }
902 
Write(napi_env env,const Rosen::Rect & nativeObject)903 napi_value JsRect::Write(napi_env env, const Rosen::Rect &nativeObject)
904 {
905     napi_value jsObject = nullptr;
906     napi_create_object(env, &jsObject);
907     bool ret = JsUtil::Object::WriteProperty(env, jsObject, "left", nativeObject.posX_);
908     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "top", nativeObject.posY_);
909     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "width", nativeObject.width_);
910     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "height", nativeObject.height_);
911     return ret ? jsObject : JsUtil::Const::Null(env);
912 }
913 
Read(napi_env env,napi_value jsObject,Rosen::Rect & nativeObject)914 bool JsRect::Read(napi_env env, napi_value jsObject, Rosen::Rect &nativeObject)
915 {
916     auto ret = JsUtil::Object::ReadProperty(env, jsObject, "left", nativeObject.posX_);
917     ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "top", nativeObject.posY_);
918     ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "width", nativeObject.width_);
919     ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "height", nativeObject.height_);
920     return ret;
921 }
922 
Write(napi_env env,const CallingWindowInfo & nativeObject)923 napi_value JsCallingWindowInfo::Write(napi_env env, const CallingWindowInfo &nativeObject)
924 {
925     napi_value jsObject = nullptr;
926     napi_create_object(env, &jsObject);
927     bool ret = JsUtil::Object::WriteProperty(env, jsObject, "rect", JsRect::Write(env, nativeObject.rect));
928     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "status", static_cast<uint32_t>(nativeObject.status));
929     return ret ? jsObject : JsUtil::Const::Null(env);
930 }
931 
Read(napi_env env,napi_value object,CallingWindowInfo & nativeObject)932 bool JsCallingWindowInfo::Read(napi_env env, napi_value object, CallingWindowInfo &nativeObject)
933 {
934     napi_value rectObject = nullptr;
935     napi_get_named_property(env, object, "rect", &rectObject);
936     auto ret = JsRect::Read(env, rectObject, nativeObject.rect);
937     uint32_t status = 0;
938     ret = ret && JsUtil::Object::ReadProperty(env, object, "status", status);
939     nativeObject.status = static_cast<Rosen::WindowStatus>(status);
940     return ret;
941 }
942 
HandleParamCheckFailure(napi_env env)943 napi_value JsTextInputClientEngine::HandleParamCheckFailure(napi_env env)
944 {
945     return JsUtil::Const::Null(env);
946 }
947 
Write(napi_env env,const Range & nativeObject)948 napi_value JsRange::Write(napi_env env, const Range &nativeObject)
949 {
950     napi_value jsObject = nullptr;
951     napi_create_object(env, &jsObject);
952     bool ret = JsUtil::Object::WriteProperty(env, jsObject, "start", nativeObject.start);
953     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "end", nativeObject.end);
954     return ret ? jsObject : JsUtil::Const::Null(env);
955 }
956 
Read(napi_env env,napi_value jsObject,Range & nativeObject)957 bool JsRange::Read(napi_env env, napi_value jsObject, Range &nativeObject)
958 {
959     auto ret = JsUtil::Object::ReadProperty(env, jsObject, "start", nativeObject.start);
960     ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "end", nativeObject.end);
961     return ret;
962 }
963 
Write(napi_env env,const InputAttribute & nativeObject)964 napi_value JsInputAttribute::Write(napi_env env, const InputAttribute &nativeObject)
965 {
966     napi_value jsObject = nullptr;
967     napi_create_object(env, &jsObject);
968     auto ret = JsUtil::Object::WriteProperty(env, jsObject, "inputPattern", nativeObject.inputPattern);
969     ret = ret && JsUtil::Object::WriteProperty(env, jsObject, "enterKeyType", nativeObject.enterKeyType);
970     ret =
971         ret
972         && JsUtil::Object::WriteProperty(env, jsObject, "isTextPreviewSupported", nativeObject.isTextPreviewSupported);
973     // not care write bundleName fail
974     JsUtil::Object::WriteProperty(env, jsObject, "bundleName", nativeObject.bundleName);
975     return ret ? jsObject : JsUtil::Const::Null(env);
976 }
977 
Read(napi_env env,napi_value jsObject,InputAttribute & nativeObject)978 bool JsInputAttribute::Read(napi_env env, napi_value jsObject, InputAttribute &nativeObject)
979 {
980     auto ret = JsUtil::Object::ReadProperty(env, jsObject, "inputPattern", nativeObject.inputPattern);
981     ret = ret && JsUtil::Object::ReadProperty(env, jsObject, "enterKeyType", nativeObject.enterKeyType);
982     ret = ret
983           && JsUtil::Object::ReadProperty(env, jsObject, "isTextPreviewSupported", nativeObject.isTextPreviewSupported);
984     // not care read bundleName fail
985     JsUtil::Object::ReadProperty(env, jsObject, "bundleName", nativeObject.bundleName);
986     return ret;
987 }
988 } // namespace MiscServices
989 } // namespace OHOS