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