1 /*
2  * Copyright (c) 2022 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_util.h"
17 
18 #include <unordered_map>
19 
20 #include <linux/input.h>
21 
22 #include "mmi_log.h"
23 #include "napi_constants.h"
24 #include "util_napi.h"
25 #include "util_napi_error.h"
26 
27 #undef MMI_LOG_TAG
28 #define MMI_LOG_TAG "JsUtil"
29 
30 namespace OHOS {
31 namespace MMI {
32 namespace {
33 std::unordered_map<int32_t, std::string> axisType = {
34     { ABS_MT_TOUCH_MAJOR, "touchmajor" },
35     { ABS_MT_TOUCH_MINOR, "touchminor" },
36     { ABS_MT_ORIENTATION, "orientation" },
37     { ABS_MT_POSITION_X, "x" },
38     { ABS_MT_POSITION_Y, "y" },
39     { ABS_MT_PRESSURE, "pressure" },
40     { ABS_MT_WIDTH_MAJOR, "toolmajor" },
41     { ABS_MT_WIDTH_MINOR, "toolminor" },
42 };
43 
44 constexpr uint32_t EVDEV_UDEV_TAG_TOUCHSCREEN = (1 << 4);
45 constexpr uint32_t EVDEV_UDEV_TAG_JOYSTICK = (1 << 6);
46 constexpr uint32_t EVDEV_UDEV_TAG_TRACKBALL = (1 << 10);
47 
48 JsUtil::DeviceType g_deviceType[] = {
49     { "keyboard", EVDEV_UDEV_TAG_KEYBOARD },
50     { "mouse", EVDEV_UDEV_TAG_MOUSE },
51     { "touchpad", EVDEV_UDEV_TAG_TOUCHPAD },
52     { "touchscreen", EVDEV_UDEV_TAG_TOUCHSCREEN },
53     { "joystick", EVDEV_UDEV_TAG_JOYSTICK },
54     { "trackball", EVDEV_UDEV_TAG_TRACKBALL },
55 };
56 } // namespace
IsSameHandle(napi_env env, napi_value handle, napi_ref ref)57 bool JsUtil::IsSameHandle(napi_env env, napi_value handle, napi_ref ref)
58 {
59     napi_handle_scope scope = nullptr;
60     napi_open_handle_scope(env, &scope);
61     napi_value handlerTemp = nullptr;
62     if (napi_get_reference_value(env, ref, &handlerTemp) != napi_ok) {
63         MMI_HILOGE("%{public}s failed", std::string(GET_REFERENCE_VALUE).c_str());
64         napi_close_handle_scope(env, scope);
65         return false;
66     }
67     bool isEqual = false;
68     if (napi_strict_equals(env, handle, handlerTemp, &isEqual) != napi_ok) {
69         MMI_HILOGE("%{public}s failed", std::string(STRICT_EQUALS).c_str());
70         napi_close_handle_scope(env, scope);
71         return false;
72     }
73     napi_close_handle_scope(env, scope);
74     return isEqual;
75 }
76 
GetDeviceInfo(sptr<CallbackInfo> cb)77 napi_value JsUtil::GetDeviceInfo(sptr<CallbackInfo> cb)
78 {
79     CHKPP(cb);
80     CHKPP(cb->env);
81     CHKPP(cb->data.device);
82     napi_value object = nullptr;
83     CHKRP(napi_create_object(cb->env, &object), CREATE_OBJECT);
84     napi_value id = nullptr;
85     CHKRP(napi_create_int32(cb->env, cb->data.device->GetId(), &id), CREATE_INT32);
86     napi_value name = nullptr;
87     CHKRP(napi_create_string_utf8(cb->env, (cb->data.device->GetName()).c_str(),
88         NAPI_AUTO_LENGTH, &name), CREATE_STRING_UTF8);
89     CHKRP(napi_set_named_property(cb->env, object, "id", id), SET_NAMED_PROPERTY);
90     CHKRP(napi_set_named_property(cb->env, object, "name", name), SET_NAMED_PROPERTY);
91     napi_value busType = nullptr;
92     CHKRP(napi_create_int32(cb->env, cb->data.device->GetBus(), &busType), CREATE_INT32);
93     CHKRP(napi_set_named_property(cb->env, object, "bus", busType), SET_NAMED_PROPERTY);
94     napi_value product = nullptr;
95     CHKRP(napi_create_int32(cb->env, cb->data.device->GetProduct(), &product), CREATE_INT32);
96     CHKRP(napi_set_named_property(cb->env, object, "product", product), SET_NAMED_PROPERTY);
97     napi_value vendor = nullptr;
98     CHKRP(napi_create_int32(cb->env, cb->data.device->GetVendor(), &vendor), CREATE_INT32);
99     CHKRP(napi_set_named_property(cb->env, object, "vendor", vendor), SET_NAMED_PROPERTY);
100     napi_value version = nullptr;
101     CHKRP(napi_create_int32(cb->env, cb->data.device->GetVersion(), &version), CREATE_INT32);
102     CHKRP(napi_set_named_property(cb->env, object, "version", version), SET_NAMED_PROPERTY);
103     napi_value uniq = nullptr;
104     CHKRP(napi_create_string_utf8(cb->env, (cb->data.device->GetUniq()).c_str(),
105         NAPI_AUTO_LENGTH, &uniq), CREATE_STRING_UTF8);
106     CHKRP(napi_set_named_property(cb->env, object, "uniq", uniq), SET_NAMED_PROPERTY);
107     napi_value phys = nullptr;
108     CHKRP(napi_create_string_utf8(cb->env, (cb->data.device->GetPhys()).c_str(),
109         NAPI_AUTO_LENGTH, &phys), CREATE_STRING_UTF8);
110     CHKRP(napi_set_named_property(cb->env, object, "phys", phys), SET_NAMED_PROPERTY);
111 
112     if (!GetDeviceSourceType(cb, object)) {
113         MMI_HILOGE("Get device source type failed");
114         return nullptr;
115     }
116     if (!GetDeviceAxisInfo(cb, object)) {
117         MMI_HILOGE("Get device axis failed");
118         return nullptr;
119     }
120     return object;
121 }
122 
GetDeviceAxisInfo(sptr<CallbackInfo> cb, napi_value &object)123 bool JsUtil::GetDeviceAxisInfo(sptr<CallbackInfo> cb, napi_value &object)
124 {
125     CHKPF(cb);
126     CHKPF(cb->env);
127     CHKPF(cb->data.device);
128     napi_value sourceType = nullptr;
129     uint32_t types = static_cast<uint32_t>(cb->data.device->GetType());
130     for (const auto &item : g_deviceType) {
131         if (types &item.typeBit) {
132             CHKRF(napi_create_string_utf8(cb->env, item.sourceTypeName.c_str(),
133                 NAPI_AUTO_LENGTH, &sourceType), CREATE_STRING_UTF8);
134             break;
135         }
136     }
137     napi_value axisRanges = nullptr;
138     CHKRF(napi_create_array(cb->env, &axisRanges), CREATE_ARRAY);
139     if (sourceType == nullptr) {
140         CHKRF(napi_set_named_property(cb->env, object, "axisRanges", axisRanges), SET_NAMED_PROPERTY);
141         MMI_HILOGD("SourceType not found");
142         return true;
143     }
144     napi_value axisRange = nullptr;
145     uint32_t i = 0;
146     for (const auto &item : cb->data.device->GetAxisInfo()) {
147         auto iter = axisType.find(item.GetAxisType());
148         if (iter == axisType.end()) {
149             MMI_HILOGD("Find axisType failed");
150             continue;
151         }
152         CHKRF(napi_create_object(cb->env, &axisRange), CREATE_OBJECT);
153         CHKRF(napi_set_named_property(cb->env, axisRange, "source", sourceType), SET_NAMED_PROPERTY);
154         napi_value axisType = nullptr;
155         CHKRF(napi_create_string_utf8(cb->env, iter->second.c_str(),
156             NAPI_AUTO_LENGTH, &axisType), CREATE_STRING_UTF8);
157         CHKRF(napi_set_named_property(cb->env, axisRange, "axis", axisType), SET_NAMED_PROPERTY);
158         napi_value min = nullptr;
159         CHKRF(napi_create_int32(cb->env, item.GetMinimum(), &min), CREATE_INT32);
160         CHKRF(napi_set_named_property(cb->env, axisRange, "min", min), SET_NAMED_PROPERTY);
161         napi_value max = nullptr;
162         CHKRF(napi_create_int32(cb->env, item.GetMaximum(), &max), CREATE_INT32);
163         CHKRF(napi_set_named_property(cb->env, axisRange, "max", max), SET_NAMED_PROPERTY);
164         napi_value fuzz = nullptr;
165         CHKRF(napi_create_int32(cb->env, item.GetFuzz(), &fuzz), CREATE_INT32);
166         CHKRF(napi_set_named_property(cb->env, axisRange, "fuzz", fuzz), SET_NAMED_PROPERTY);
167         napi_value flat = nullptr;
168         CHKRF(napi_create_int32(cb->env, item.GetFlat(), &flat), CREATE_INT32);
169         CHKRF(napi_set_named_property(cb->env, axisRange, "flat", flat), SET_NAMED_PROPERTY);
170         napi_value resolution = nullptr;
171         CHKRF(napi_create_int32(cb->env, item.GetResolution(), &resolution), CREATE_INT32);
172         CHKRF(napi_set_named_property(cb->env, axisRange, "resolution", resolution), SET_NAMED_PROPERTY);
173         CHKRF(napi_set_element(cb->env, axisRanges, i, axisRange), SET_ELEMENT);
174         ++i;
175     }
176     CHKRF(napi_set_named_property(cb->env, object, "axisRanges", axisRanges), SET_NAMED_PROPERTY);
177     return true;
178 }
179 
GetDeviceSourceType(sptr<CallbackInfo> cb, napi_value &object)180 bool JsUtil::GetDeviceSourceType(sptr<CallbackInfo> cb, napi_value &object)
181 {
182     CHKPF(cb);
183     CHKPF(cb->env);
184     CHKPF(cb->data.device);
185     uint32_t types = static_cast<uint32_t>(cb->data.device->GetType());
186     std::vector<std::string> sources;
187     for (const auto &item : g_deviceType) {
188         if (types &item.typeBit) {
189             sources.push_back(item.sourceTypeName);
190         }
191     }
192     napi_value devSources = nullptr;
193     CHKRF(napi_create_array(cb->env, &devSources), CREATE_ARRAY);
194     napi_value value = nullptr;
195     for (size_t i = 0; i < sources.size(); ++i) {
196         CHKRF(napi_create_string_utf8(cb->env, sources[i].c_str(), NAPI_AUTO_LENGTH, &value),
197             CREATE_STRING_UTF8);
198         CHKRF(napi_set_element(cb->env, devSources, i, value), SET_ELEMENT);
199     }
200     CHKRF(napi_set_named_property(cb->env, object, "sources", devSources), SET_NAMED_PROPERTY);
201     return true;
202 }
203 
TypeOf(napi_env env, napi_value value, napi_valuetype type)204 bool JsUtil::TypeOf(napi_env env, napi_value value, napi_valuetype type)
205 {
206     napi_valuetype valueType = napi_undefined;
207     CHKRF(napi_typeof(env, value, &valueType), TYPEOF);
208     if (valueType != type) {
209         return false;
210     }
211     return true;
212 }
213 
DeleteCallbackInfo(std::unique_ptr<CallbackInfo> callback)214 void JsUtil::DeleteCallbackInfo(std::unique_ptr<CallbackInfo> callback)
215 {
216     CALL_DEBUG_ENTER;
217     if (callback->ref != nullptr && callback->env != nullptr) {
218         CHKRV(napi_delete_reference(callback->env, callback->ref), DELETE_REFERENCE);
219         callback->env = nullptr;
220     }
221 }
222 
CheckType(napi_env env, napi_value value, napi_valuetype type)223 bool JsUtil::CheckType(napi_env env, napi_value value, napi_valuetype type)
224 {
225     napi_valuetype valuetype = napi_undefined;
226     napi_typeof(env, value, &valuetype);
227     return valuetype == type;
228 }
229 
ParseDouble(napi_env env, napi_value value, double& result)230 bool JsUtil::ParseDouble(napi_env env, napi_value value, double& result)
231 {
232     if (!CheckType(env, value, napi_number)) {
233         MMI_HILOGE("ParseDouble type not number");
234         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "parameter", "number");
235         return false;
236     }
237     if (napi_get_value_double(env, value, &result) != napi_ok) {
238         MMI_HILOGE("ParseDouble cannot get value double");
239         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "parameter", "double");
240         return false;
241     }
242     return true;
243 }
244 
IsArray(napi_env env, napi_value value)245 bool JsUtil::IsArray(napi_env env, napi_value value)
246 {
247     bool isArray = false;
248     if (napi_is_array(env, value, &isArray) != napi_ok) {
249         MMI_HILOGE("napi_is_array failed");
250         return false;
251     }
252     return isArray;
253 }
254 
ParseInt32(napi_env env, napi_value value, int32_t& result)255 bool JsUtil::ParseInt32(napi_env env, napi_value value, int32_t& result)
256 {
257     if (!CheckType(env, value, napi_number)) {
258         MMI_HILOGE("ParseInt32 type not number");
259         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "number");
260         return false;
261     }
262     if (napi_get_value_int32(env, value, &result) != napi_ok) {
263         MMI_HILOGE("ParseInt32 cannot get value int32_t");
264         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "int32_t");
265         return false;
266     }
267     return true;
268 }
269 
ParseString(napi_env env, napi_value value, char* result)270 bool JsUtil::ParseString(napi_env env, napi_value value, char* result)
271 {
272     if (!CheckType(env, value, napi_string)) {
273         MMI_HILOGE("ParseString type not string");
274         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "string");
275         return false;
276     }
277 
278     size_t len = 0;
279     if (napi_get_value_string_utf8(env, value, result, MAX_STRING_LEN - 1, &len) != napi_ok) {
280         MMI_HILOGE("ParseString cannot get value string");
281         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "char[]");
282         return false;
283     }
284     return true;
285 }
286 
ParseBool(napi_env env, napi_value value, bool& result)287 bool JsUtil::ParseBool(napi_env env, napi_value value, bool& result)
288 {
289     if (!CheckType(env, value, napi_boolean)) {
290         MMI_HILOGE("ParseBool type not boolean");
291         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "boolean");
292         return false;
293     }
294     if (napi_get_value_bool(env, value, &result) != napi_ok) {
295         MMI_HILOGE("ParseBool cannot get value bool");
296         THROWERR_API9(env, COMMON_PARAMETER_ERROR, "element", "bool");
297         return false;
298     }
299     return true;
300 }
301 
GetNapiInt32(napi_env env, int32_t code)302 napi_value JsUtil::GetNapiInt32(napi_env env, int32_t code)
303 {
304     CALL_DEBUG_ENTER;
305     napi_value ret = nullptr;
306     CHKRP(napi_create_int32(env, code, &ret), CREATE_INT32);
307     return ret;
308 }
309 } // namespace MMI
310 } // namespace OHOS