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