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