1 /*
2 * Copyright (c) 2021 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_input_method.h"
17
18 #include "event_handler.h"
19 #include "event_runner.h"
20 #include "input_method_controller.h"
21 #include "input_method_property.h"
22 #include "napi/native_api.h"
23 #include "js_util.h"
24 #include "napi/native_node_api.h"
25 #include "string_ex.h"
26
27 namespace OHOS {
28 namespace MiscServices {
Init(napi_env env,napi_value exports)29 napi_value JsInputMethod::Init(napi_env env, napi_value exports)
30 {
31 napi_property_descriptor descriptor[] = {
32 DECLARE_NAPI_FUNCTION("switchInputMethod", SwitchInputMethod),
33 DECLARE_NAPI_FUNCTION("getCurrentInputMethod", GetCurrentInputMethod),
34 DECLARE_NAPI_FUNCTION("getCurrentInputMethodSubtype", GetCurrentInputMethodSubtype),
35 DECLARE_NAPI_FUNCTION("getDefaultInputMethod", GetDefaultInputMethod),
36 DECLARE_NAPI_FUNCTION("getSystemInputMethodConfigAbility", GetSystemInputMethodConfigAbility),
37 DECLARE_NAPI_FUNCTION("switchCurrentInputMethodSubtype", SwitchCurrentInputMethodSubtype),
38 DECLARE_NAPI_FUNCTION("switchCurrentInputMethodAndSubtype", SwitchCurrentInputMethodAndSubtype),
39 };
40 NAPI_CALL(
41 env, napi_define_properties(env, exports, sizeof(descriptor) / sizeof(napi_property_descriptor), descriptor));
42 return exports;
43 };
44
GetInputMethodProperty(napi_env env,napi_value argv,std::shared_ptr<SwitchInputMethodContext> ctxt)45 napi_status JsInputMethod::GetInputMethodProperty(
46 napi_env env, napi_value argv, std::shared_ptr<SwitchInputMethodContext> ctxt)
47 {
48 napi_valuetype valueType = napi_undefined;
49 napi_status status = napi_generic_failure;
50 napi_typeof(env, argv, &valueType);
51 if (valueType != napi_object) {
52 IMSA_HILOGE("valueType error");
53 return status;
54 }
55 napi_value result = nullptr;
56 napi_get_named_property(env, argv, "name", &result);
57 status = JsUtils::GetValue(env, result, ctxt->packageName);
58 CHECK_RETURN(status == napi_ok, "get ctxt->packageName failed!", status);
59 result = nullptr;
60 napi_get_named_property(env, argv, "id", &result);
61 status = JsUtils::GetValue(env, result, ctxt->methodId);
62 CHECK_RETURN(status == napi_ok, "get ctxt->methodId failed!", status);
63 if (ctxt->packageName.empty() || ctxt->methodId.empty()) {
64 result = nullptr;
65 napi_get_named_property(env, argv, "packageName", &result);
66 status = JsUtils::GetValue(env, result, ctxt->packageName);
67 CHECK_RETURN(status == napi_ok, "get ctxt->packageName failed!", status);
68
69 result = nullptr;
70 napi_get_named_property(env, argv, "methodId", &result);
71 status = JsUtils::GetValue(env, result, ctxt->methodId);
72 CHECK_RETURN(status == napi_ok, "get ctxt->methodId failed!", status);
73 }
74 PARAM_CHECK_RETURN(env, (!ctxt->packageName.empty() && !ctxt->methodId.empty()), "JsInputMethod, Parameter error.",
75 TYPE_NONE, napi_invalid_arg);
76 IMSA_HILOGD("methodId:%{public}s, packageName:%{public}s", ctxt->methodId.c_str(), ctxt->packageName.c_str());
77 return napi_ok;
78 }
79
GetInputMethodSubProperty(napi_env env,napi_value argv,std::shared_ptr<SwitchInputMethodContext> ctxt)80 napi_status JsInputMethod::GetInputMethodSubProperty(
81 napi_env env, napi_value argv, std::shared_ptr<SwitchInputMethodContext> ctxt)
82 {
83 napi_valuetype valueType = napi_undefined;
84 napi_status status = napi_generic_failure;
85 status = napi_typeof(env, argv, &valueType);
86 if (valueType == napi_object) {
87 napi_value result = nullptr;
88 status = napi_get_named_property(env, argv, "name", &result);
89 PARAM_CHECK_RETURN(env, status == napi_ok, " name ", TYPE_STRING, status);
90 status = JsUtils::GetValue(env, result, ctxt->name);
91 CHECK_RETURN(status == napi_ok, "get ctxt->name failed!", status);
92 result = nullptr;
93 status = napi_get_named_property(env, argv, "id", &result);
94 PARAM_CHECK_RETURN(env, status == napi_ok, " id ", TYPE_STRING, status);
95 status = JsUtils::GetValue(env, result, ctxt->id);
96 CHECK_RETURN(status == napi_ok, "get ctxt->id failed!", status);
97 IMSA_HILOGD("name:%{public}s and id:%{public}s", ctxt->name.c_str(), ctxt->id.c_str());
98 }
99 return status;
100 }
101
GetJsInputMethodProperty(napi_env env,const Property & property)102 napi_value JsInputMethod::GetJsInputMethodProperty(napi_env env, const Property &property)
103 {
104 napi_value prop = nullptr;
105 napi_create_object(env, &prop);
106
107 napi_value packageName = nullptr;
108 napi_create_string_utf8(env, property.name.c_str(), NAPI_AUTO_LENGTH, &packageName);
109 napi_set_named_property(env, prop, "packageName", packageName);
110 napi_set_named_property(env, prop, "name", packageName);
111
112 napi_value methodId = nullptr;
113 napi_create_string_utf8(env, property.id.c_str(), NAPI_AUTO_LENGTH, &methodId);
114 napi_set_named_property(env, prop, "methodId", methodId);
115 napi_set_named_property(env, prop, "id", methodId);
116
117 napi_value icon = nullptr;
118 napi_create_string_utf8(env, property.icon.c_str(), NAPI_AUTO_LENGTH, &icon);
119 napi_set_named_property(env, prop, "icon", icon);
120
121 napi_value iconId = nullptr;
122 napi_create_int32(env, property.iconId, &iconId);
123 napi_set_named_property(env, prop, "iconId", iconId);
124
125 napi_value label = nullptr;
126 napi_create_string_utf8(env, property.label.c_str(), NAPI_AUTO_LENGTH, &label);
127 napi_set_named_property(env, prop, "label", label);
128
129 napi_value labelId = nullptr;
130 napi_create_int32(env, property.labelId, &labelId);
131 napi_set_named_property(env, prop, "labelId", labelId);
132 return prop;
133 }
134
GetJsInputMethodSubProperty(napi_env env,const SubProperty & subProperty)135 napi_value JsInputMethod::GetJsInputMethodSubProperty(napi_env env, const SubProperty &subProperty)
136 {
137 napi_value prop = nullptr;
138 napi_create_object(env, &prop);
139
140 napi_value id = nullptr;
141 napi_create_string_utf8(env, subProperty.id.c_str(), NAPI_AUTO_LENGTH, &id);
142 napi_set_named_property(env, prop, "id", id);
143
144 napi_value label = nullptr;
145 napi_create_string_utf8(env, subProperty.label.c_str(), NAPI_AUTO_LENGTH, &label);
146 napi_set_named_property(env, prop, "label", label);
147
148 napi_value labelId = nullptr;
149 napi_create_int32(env, subProperty.labelId, &labelId);
150 napi_set_named_property(env, prop, "labelId", labelId);
151
152 napi_value name = nullptr;
153 napi_create_string_utf8(env, subProperty.name.c_str(), NAPI_AUTO_LENGTH, &name);
154 napi_set_named_property(env, prop, "name", name);
155
156 napi_value mode = nullptr;
157 napi_create_string_utf8(env, subProperty.mode.c_str(), NAPI_AUTO_LENGTH, &mode);
158 napi_set_named_property(env, prop, "mode", mode);
159
160 napi_value locale = nullptr;
161 napi_create_string_utf8(env, subProperty.locale.c_str(), NAPI_AUTO_LENGTH, &locale);
162 napi_set_named_property(env, prop, "locale", locale);
163
164 napi_value language = nullptr;
165 napi_create_string_utf8(env, subProperty.language.c_str(), NAPI_AUTO_LENGTH, &language);
166 napi_set_named_property(env, prop, "language", language);
167
168 napi_value icon = nullptr;
169 napi_create_string_utf8(env, subProperty.icon.c_str(), NAPI_AUTO_LENGTH, &icon);
170 napi_set_named_property(env, prop, "icon", icon);
171
172 napi_value iconId = nullptr;
173 napi_create_int32(env, subProperty.iconId, &iconId);
174 napi_set_named_property(env, prop, "iconId", iconId);
175 return prop;
176 }
177
GetJsInputConfigElement(napi_env env,const OHOS::AppExecFwk::ElementName & elementName)178 napi_value JsInputMethod::GetJsInputConfigElement(napi_env env, const OHOS::AppExecFwk::ElementName &elementName)
179 {
180 napi_value element = nullptr;
181 napi_create_object(env, &element);
182
183 napi_value bundleName = nullptr;
184 napi_create_string_utf8(env, elementName.GetBundleName().c_str(), NAPI_AUTO_LENGTH, &bundleName);
185 napi_set_named_property(env, element, "bundleName", bundleName);
186
187 napi_value moduleName = nullptr;
188 napi_create_string_utf8(env, elementName.GetModuleName().c_str(), NAPI_AUTO_LENGTH, &moduleName);
189 napi_set_named_property(env, element, "moduleName", moduleName);
190
191 napi_value abilityName = nullptr;
192 napi_create_string_utf8(env, elementName.GetAbilityName().c_str(), NAPI_AUTO_LENGTH, &abilityName);
193 napi_set_named_property(env, element, "abilityName", abilityName);
194
195 return element;
196 }
197
GetJSInputMethodSubProperties(napi_env env,const std::vector<SubProperty> & subProperties)198 napi_value JsInputMethod::GetJSInputMethodSubProperties(napi_env env, const std::vector<SubProperty> &subProperties)
199 {
200 uint32_t index = 0;
201 napi_value prop = nullptr;
202 napi_create_array(env, &prop);
203 if (prop == nullptr) {
204 IMSA_HILOGE("create array failed");
205 return prop;
206 }
207 for (const auto &subproperty : subProperties) {
208 napi_value pro = GetJsInputMethodSubProperty(env, subproperty);
209 napi_set_element(env, prop, index, pro);
210 index++;
211 }
212 return prop;
213 }
214
GetJSInputMethodProperties(napi_env env,const std::vector<Property> & properties)215 napi_value JsInputMethod::GetJSInputMethodProperties(napi_env env, const std::vector<Property> &properties)
216 {
217 uint32_t index = 0;
218 napi_value prop = nullptr;
219 napi_create_array(env, &prop);
220 if (prop == nullptr) {
221 IMSA_HILOGE("create array failed");
222 return prop;
223 }
224 for (const auto &property : properties) {
225 napi_value pro = GetJsInputMethodProperty(env, property);
226 napi_set_element(env, prop, index, pro);
227 index++;
228 }
229 return prop;
230 }
231
SwitchInputMethod(napi_env env,napi_callback_info info)232 napi_value JsInputMethod::SwitchInputMethod(napi_env env, napi_callback_info info)
233 {
234 auto ctxt = std::make_shared<SwitchInputMethodContext>();
235 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
236 PARAM_CHECK_RETURN(env, argc > 0, "at least 1 parameter", TYPE_NONE, napi_invalid_arg);
237 napi_valuetype valueType = napi_undefined;
238 napi_typeof(env, argv[0], &valueType);
239 PARAM_CHECK_RETURN(env, valueType == napi_object || valueType == napi_string, "type must be object or string",
240 TYPE_NONE, napi_invalid_arg);
241 napi_status status = napi_generic_failure;
242 if (valueType == napi_object) {
243 ctxt->trigger = SwitchTrigger::CURRENT_IME;
244 status = GetInputMethodProperty(env, argv[0], ctxt);
245 } else {
246 status = JsUtils::GetValue(env, argv[0], ctxt->packageName);
247 ctxt->trigger = SwitchTrigger::SYSTEM_APP;
248 napi_valuetype type = napi_undefined;
249 napi_typeof(env, argv[1], &type);
250 if (argc > 1 && type == napi_string) {
251 JsUtils::GetValue(env, argv[1], ctxt->id);
252 }
253 }
254 return status;
255 };
256 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
257 napi_status status = napi_get_boolean(env, ctxt->isSwitchInput, result);
258 return status;
259 };
260 auto exec = [ctxt](AsyncCall::Context *ctx) {
261 int32_t errCode =
262 InputMethodController::GetInstance()->SwitchInputMethod(ctxt->trigger, ctxt->packageName, ctxt->id);
263 if (errCode == ErrorCode::NO_ERROR) {
264 ctxt->status = napi_ok;
265 ctxt->SetState(ctxt->status);
266 ctxt->isSwitchInput = true;
267 } else {
268 IMSA_HILOGE("exec SwitchInputMethod failed ret: %{public}d", errCode);
269 ctxt->SetErrorCode(errCode);
270 }
271 };
272 ctxt->SetAction(std::move(input), std::move(output));
273 // 2 means JsAPI:switchInputMethod has 2 params at most.
274 AsyncCall asyncCall(env, info, ctxt, 2);
275 return asyncCall.Call(env, exec, "switchInputMethod");
276 }
277
GetCurrentInputMethod(napi_env env,napi_callback_info info)278 napi_value JsInputMethod::GetCurrentInputMethod(napi_env env, napi_callback_info info)
279 {
280 std::shared_ptr<Property> property = InputMethodController::GetInstance()->GetCurrentInputMethod();
281 if (property == nullptr) {
282 IMSA_HILOGE("get current inputmethod is nullptr");
283 napi_value result = nullptr;
284 napi_get_null(env, &result);
285 return result;
286 }
287 return GetJsInputMethodProperty(env, *property);
288 }
289
GetCurrentInputMethodSubtype(napi_env env,napi_callback_info info)290 napi_value JsInputMethod::GetCurrentInputMethodSubtype(napi_env env, napi_callback_info info)
291 {
292 std::shared_ptr<SubProperty> subProperty = InputMethodController::GetInstance()->GetCurrentInputMethodSubtype();
293 if (subProperty == nullptr) {
294 IMSA_HILOGE("get current inputmethodsubtype is nullptr");
295 napi_value result = nullptr;
296 napi_get_null(env, &result);
297 return result;
298 }
299 return GetJsInputMethodSubProperty(env, *subProperty);
300 }
301
GetDefaultInputMethod(napi_env env,napi_callback_info info)302 napi_value JsInputMethod::GetDefaultInputMethod(napi_env env, napi_callback_info info)
303 {
304 std::shared_ptr<Property> property;
305 int32_t ret = InputMethodController::GetInstance()->GetDefaultInputMethod(property);
306 if (property == nullptr) {
307 IMSA_HILOGE("get default input method is nullptr");
308 napi_value result = nullptr;
309 napi_get_null(env, &result);
310 return result;
311 }
312 if (ret != ErrorCode::NO_ERROR) {
313 JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to get default input method", TYPE_NONE);
314 return JsUtil::Const::Null(env);
315 }
316 return GetJsInputMethodProperty(env, *property);
317 }
318
GetSystemInputMethodConfigAbility(napi_env env,napi_callback_info info)319 napi_value JsInputMethod::GetSystemInputMethodConfigAbility(napi_env env, napi_callback_info info)
320 {
321 OHOS::AppExecFwk::ElementName inputMethodConfig;
322 int32_t ret = InputMethodController::GetInstance()->GetInputMethodConfig(inputMethodConfig);
323 if (ret != ErrorCode::NO_ERROR) {
324 JsUtils::ThrowException(env, JsUtils::Convert(ret), "failed to get input method config", TYPE_NONE);
325 return JsUtil::Const::Null(env);
326 }
327 return GetJsInputConfigElement(env, inputMethodConfig);
328 }
329
SwitchCurrentInputMethodSubtype(napi_env env,napi_callback_info info)330 napi_value JsInputMethod::SwitchCurrentInputMethodSubtype(napi_env env, napi_callback_info info)
331 {
332 auto ctxt = std::make_shared<SwitchInputMethodContext>();
333 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
334 PARAM_CHECK_RETURN(env, argc > 0, "should has one parameter. ", TYPE_NONE, napi_invalid_arg);
335 napi_valuetype valueType = napi_undefined;
336 napi_typeof(env, argv[0], &valueType);
337 PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodSubtype: ", TYPE_OBJECT, napi_object_expected);
338 napi_status status = GetInputMethodSubProperty(env, argv[0], ctxt);
339 return status;
340 };
341 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
342 napi_status status = napi_get_boolean(env, ctxt->isSwitchInput, result);
343 IMSA_HILOGE("output napi_get_boolean != nullptr[%{public}d]", result != nullptr);
344 return status;
345 };
346 auto exec = [ctxt](AsyncCall::Context *ctx) {
347 int32_t errCode =
348 InputMethodController::GetInstance()->SwitchInputMethod(SwitchTrigger::CURRENT_IME, ctxt->name, ctxt->id);
349 if (errCode == ErrorCode::NO_ERROR) {
350 IMSA_HILOGI("exec SwitchInputMethod success");
351 ctxt->status = napi_ok;
352 ctxt->SetState(ctxt->status);
353 ctxt->isSwitchInput = true;
354 } else {
355 ctxt->SetErrorCode(errCode);
356 }
357 };
358 ctxt->SetAction(std::move(input), std::move(output));
359 // 2 means JsAPI:switchCurrentInputMethodSubtype has 2 params at most.
360 AsyncCall asyncCall(env, info, ctxt, 2);
361 return asyncCall.Call(env, exec, "switchCurrentInputMethodSubtype");
362 }
363
SwitchCurrentInputMethodAndSubtype(napi_env env,napi_callback_info info)364 napi_value JsInputMethod::SwitchCurrentInputMethodAndSubtype(napi_env env, napi_callback_info info)
365 {
366 auto ctxt = std::make_shared<SwitchInputMethodContext>();
367 auto input = [ctxt](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
368 PARAM_CHECK_RETURN(env, argc > 1, "should has two parameter.", TYPE_NONE, napi_invalid_arg);
369 napi_valuetype valueType = napi_undefined;
370 napi_typeof(env, argv[0], &valueType);
371 PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodProperty: ", TYPE_OBJECT, napi_object_expected);
372 napi_typeof(env, argv[1], &valueType);
373 PARAM_CHECK_RETURN(env, valueType == napi_object, "inputMethodSubtype: ", TYPE_OBJECT, napi_object_expected);
374 napi_status status = GetInputMethodSubProperty(env, argv[1], ctxt);
375 return status;
376 };
377 auto output = [ctxt](napi_env env, napi_value *result) -> napi_status {
378 napi_status status = napi_get_boolean(env, ctxt->isSwitchInput, result);
379 IMSA_HILOGE("output napi_get_boolean != nullptr[%{public}d]", result != nullptr);
380 return status;
381 };
382 auto exec = [ctxt](AsyncCall::Context *ctx) {
383 int32_t errCode =
384 InputMethodController::GetInstance()->SwitchInputMethod(SwitchTrigger::CURRENT_IME, ctxt->name, ctxt->id);
385 if (errCode == ErrorCode::NO_ERROR) {
386 IMSA_HILOGI("exec SwitchInputMethod success");
387 ctxt->status = napi_ok;
388 ctxt->SetState(ctxt->status);
389 ctxt->isSwitchInput = true;
390 } else {
391 ctxt->SetErrorCode(errCode);
392 }
393 };
394 ctxt->SetAction(std::move(input), std::move(output));
395 // 3 means JsAPI:switchCurrentInputMethodAndSubtype has 3 params at most.
396 AsyncCall asyncCall(env, info, ctxt, 3);
397 return asyncCall.Call(env, exec, "switchCurrentInputMethodAndSubtype");
398 }
399 } // namespace MiscServices
400 } // namespace OHOS