1 /* 2 * Copyright (c) 2021-2023 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 #ifndef INTERFACE_KITS_JS_GET_INPUT_METHOD_CONTROLLER_H 16 #define INTERFACE_KITS_JS_GET_INPUT_METHOD_CONTROLLER_H 17 18 #include "async_call.h" 19 #include "controller_listener.h" 20 #include "event_handler.h" 21 #include "global.h" 22 #include "js_callback_object.h" 23 #include "js_input_method.h" 24 #include "js_message_handler_info.h" 25 #include "msg_handler_callback_interface.h" 26 27 namespace OHOS { 28 namespace MiscServices { 29 struct AttachInfo { 30 std::chrono::system_clock::time_point timestamp{}; 31 InputAttribute attribute; 32 bool operator==(const AttachInfo &info) const 33 { 34 return (timestamp == info.timestamp && attribute == info.attribute); 35 } 36 }; 37 38 struct HandleContext : public AsyncCall::Context { 39 bool isHandle = false; 40 napi_status status = napi_generic_failure; HandleContextHandleContext41 HandleContext() : Context(nullptr, nullptr){}; HandleContextHandleContext42 HandleContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 43 operatorHandleContext44 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 45 { 46 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 47 return Context::operator()(env, argc, argv, self); 48 } operatorHandleContext49 napi_status operator()(napi_env env, napi_value *result) override 50 { 51 if (status != napi_ok) { 52 output_ = nullptr; 53 return status; 54 } 55 return Context::operator()(env, result); 56 } 57 }; 58 59 struct AttachContext : public AsyncCall::Context { 60 sptr<OnTextChangedListener> textListener; 61 InputAttribute attribute; 62 bool showKeyboard = false; 63 int32_t requestKeyboardReason = 0; 64 TextConfig textConfig; 65 AttachInfo info; AttachContextAttachContext66 AttachContext() : Context(nullptr, nullptr){}; AttachContextAttachContext67 AttachContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 68 operatorAttachContext69 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 70 { 71 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 72 return Context::operator()(env, argc, argv, self); 73 } operatorAttachContext74 napi_status operator()(napi_env env, napi_value *result) override 75 { 76 if (status_ != napi_ok) { 77 output_ = nullptr; 78 return status_; 79 } 80 return Context::operator()(env, result); 81 } 82 }; 83 84 struct SetCallingWindowContext : public AsyncCall::Context { 85 int32_t windID = 0; SetCallingWindowContextSetCallingWindowContext86 SetCallingWindowContext() : Context(nullptr, nullptr){}; SetCallingWindowContextSetCallingWindowContext87 SetCallingWindowContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 88 operatorSetCallingWindowContext89 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 90 { 91 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 92 return Context::operator()(env, argc, argv, self); 93 } operatorSetCallingWindowContext94 napi_status operator()(napi_env env, napi_value *result) override 95 { 96 if (status_ != napi_ok) { 97 output_ = nullptr; 98 return status_; 99 } 100 return Context::operator()(env, result); 101 } 102 }; 103 104 struct UpdateCursorContext : public AsyncCall::Context { 105 CursorInfo cursorInfo; UpdateCursorContextUpdateCursorContext106 UpdateCursorContext() : Context(nullptr, nullptr){}; UpdateCursorContextUpdateCursorContext107 UpdateCursorContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 108 operatorUpdateCursorContext109 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 110 { 111 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 112 return Context::operator()(env, argc, argv, self); 113 } operatorUpdateCursorContext114 napi_status operator()(napi_env env, napi_value *result) override 115 { 116 if (status_ != napi_ok) { 117 output_ = nullptr; 118 return status_; 119 } 120 return Context::operator()(env, result); 121 } 122 }; 123 124 struct ChangeSelectionContext : public AsyncCall::Context { 125 std::u16string text; 126 int32_t start = 0; 127 int32_t end = 0; ChangeSelectionContextChangeSelectionContext128 ChangeSelectionContext() : Context(nullptr, nullptr){}; ChangeSelectionContextChangeSelectionContext129 ChangeSelectionContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 130 operatorChangeSelectionContext131 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 132 { 133 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 134 return Context::operator()(env, argc, argv, self); 135 } operatorChangeSelectionContext136 napi_status operator()(napi_env env, napi_value *result) override 137 { 138 if (status_ != napi_ok) { 139 output_ = nullptr; 140 return status_; 141 } 142 return Context::operator()(env, result); 143 } 144 }; 145 146 struct UpdateAttributeContext : public AsyncCall::Context { 147 InputAttribute attribute; 148 Configuration configuration; UpdateAttributeContextUpdateAttributeContext149 UpdateAttributeContext() : Context(nullptr, nullptr){}; UpdateAttributeContextUpdateAttributeContext150 UpdateAttributeContext(InputAction input, OutputAction output) : Context(std::move(input), std::move(output)){}; 151 operatorUpdateAttributeContext152 napi_status operator()(napi_env env, size_t argc, napi_value *argv, napi_value self) override 153 { 154 CHECK_RETURN(self != nullptr, "self is nullptr!", napi_invalid_arg); 155 return Context::operator()(env, argc, argv, self); 156 } operatorUpdateAttributeContext157 napi_status operator()(napi_env env, napi_value *result) override 158 { 159 if (status_ != napi_ok) { 160 output_ = nullptr; 161 return status_; 162 } 163 return Context::operator()(env, result); 164 } 165 }; 166 167 class JsGetInputMethodController : public ControllerListener { 168 public: 169 JsGetInputMethodController() = default; 170 ~JsGetInputMethodController() = default; 171 static napi_value Init(napi_env env, napi_value info); 172 static napi_value GetController(napi_env env, napi_callback_info cbInfo); 173 static napi_value GetInputMethodController(napi_env env, napi_callback_info cbInfo); 174 static std::shared_ptr<JsGetInputMethodController> GetInstance(); 175 static napi_value HandleSoftKeyboard(napi_env env, napi_callback_info info, std::function<int32_t()> callback, 176 bool isOutput, bool needThrowException); 177 static napi_value Attach(napi_env env, napi_callback_info info); 178 static napi_value Detach(napi_env env, napi_callback_info info); 179 static napi_value ShowTextInput(napi_env env, napi_callback_info info); 180 static napi_value HideTextInput(napi_env env, napi_callback_info info); 181 static napi_value DiscardTypingText(napi_env env, napi_callback_info info); 182 static napi_value SetCallingWindow(napi_env env, napi_callback_info info); 183 static napi_value UpdateCursor(napi_env env, napi_callback_info info); 184 static napi_value ChangeSelection(napi_env env, napi_callback_info info); 185 static napi_value UpdateAttribute(napi_env env, napi_callback_info info); 186 static napi_value HideSoftKeyboard(napi_env env, napi_callback_info info); 187 static napi_value ShowSoftKeyboard(napi_env env, napi_callback_info info); 188 static napi_value StopInputSession(napi_env env, napi_callback_info info); 189 static napi_value StopInput(napi_env env, napi_callback_info info); 190 static napi_value Subscribe(napi_env env, napi_callback_info info); 191 static napi_value UnSubscribe(napi_env env, napi_callback_info info); 192 static napi_value SendMessage(napi_env env, napi_callback_info info); 193 static napi_value RecvMessage(napi_env env, napi_callback_info info); 194 void OnSelectByRange(int32_t start, int32_t end) override; 195 void OnSelectByMovement(int32_t direction) override; 196 void InsertText(const std::u16string &text); 197 void DeleteRight(int32_t length); 198 void DeleteLeft(int32_t length); 199 void SendKeyboardStatus(const KeyboardStatus &status); 200 void SendFunctionKey(const FunctionKey &functionKey); 201 void MoveCursor(const Direction direction); 202 void HandleExtendAction(int32_t action); 203 std::u16string GetText(const std::string &type, int32_t number); 204 int32_t GetTextIndexAtCursor(); 205 int32_t SetPreviewText(const std::u16string &text, const Range &range); 206 void FinishTextPreview(); 207 208 class JsMessageHandler : public MsgHandlerCallbackInterface { 209 public: JsMessageHandler(napi_env env,napi_value onTerminated,napi_value onMessage)210 explicit JsMessageHandler(napi_env env, napi_value onTerminated, napi_value onMessage) 211 : jsMessageHandler_(std::make_shared<JSMsgHandlerCallbackObject>(env, onTerminated, onMessage)) {}; ~JsMessageHandler()212 virtual ~JsMessageHandler() {}; 213 int32_t OnTerminated() override; 214 int32_t OnMessage(const ArrayBuffer &arrayBuffer) override; 215 private: 216 std::mutex callbackObjectMutex_; 217 std::shared_ptr<JSMsgHandlerCallbackObject> jsMessageHandler_ = nullptr; 218 }; 219 private: 220 static napi_value JsConstructor(napi_env env, napi_callback_info cbinfo); 221 static napi_value GetIMController(napi_env env, napi_callback_info cbInfo, bool needThrowException); 222 static napi_value CreateSelectRange(napi_env env, int32_t start, int32_t end); 223 static napi_value CreateSelectMovement(napi_env env, int32_t direction); 224 static napi_value CreateSendFunctionKey(napi_env env, int32_t functionKey); 225 void RegisterListener(napi_value callback, std::string type, std::shared_ptr<JSCallbackObject> callbackObj); 226 void UnRegisterListener(napi_value callback, std::string type); 227 bool IsRegister(const std::string &type); 228 void UpdateTextPreviewState(const std::string &type); 229 static bool GetValue(napi_env env, napi_value in, CursorInfo &out); 230 static bool GetValue(napi_env env, napi_value in, InputAttribute &out); 231 static bool GetValue(napi_env env, napi_value in, TextConfig &out); 232 static bool GetValue(napi_env env, napi_value in, Range &out); 233 static napi_value GetAttachOptionsValue(napi_env env, napi_callback_info cbinfo, AttachOptions &attachOptions); 234 static napi_value GetJsKeyboardStatusProperty(napi_env env); 235 static napi_value GetJsEnterKeyTypeProperty(napi_env env); 236 static napi_value GetJsTextInputTypeProperty(napi_env env); 237 static napi_value GetJsDirectionProperty(napi_env env); 238 static napi_value GetJsExtendActionProperty(napi_env env); 239 static napi_value GetJsEnabledStateProperty(napi_env env); 240 static napi_value GetJsCapitalizeModeProperty(napi_env env); 241 static napi_value GetJsRequestKeyboardReasonProperty(napi_env env); 242 static std::shared_ptr<AppExecFwk::EventHandler> GetEventHandler(); 243 static bool IsTextPreviewSupported(); 244 static const std::set<std::string> TEXT_EVENT_TYPE; 245 static constexpr int32_t MAX_TIMEOUT = 2500; 246 struct UvEntry { 247 std::vector<std::shared_ptr<JSCallbackObject>> vecCopy; 248 std::string type; 249 std::string text; 250 int32_t start = 0; 251 int32_t end = 0; 252 int32_t direction = 0; 253 int32_t length = 0; 254 int32_t action = 0; 255 int32_t keyboardStatus = 0; 256 int32_t enterKeyType = 0; 257 int32_t number = 0; 258 std::shared_ptr<BlockData<std::string>> textResultHandler; 259 std::shared_ptr<BlockData<std::int32_t>> indexResultHandler; UvEntryUvEntry260 explicit UvEntry(const std::vector<std::shared_ptr<JSCallbackObject>> &cbVec, const std::string &type) 261 : vecCopy(cbVec), type(type) 262 { 263 } 264 }; 265 using EntrySetter = std::function<void(UvEntry &)>; 266 std::shared_ptr<UvEntry> GetEntry(const std::string &type, EntrySetter entrySetter = nullptr); 267 std::recursive_mutex mutex_; 268 std::map<std::string, std::vector<std::shared_ptr<JSCallbackObject>>> jsCbMap_; 269 static std::mutex controllerMutex_; 270 static std::shared_ptr<JsGetInputMethodController> controller_; 271 static const std::string IMC_CLASS_NAME; 272 static thread_local napi_ref IMCRef_; 273 static std::mutex eventHandlerMutex_; 274 static std::shared_ptr<AppExecFwk::EventHandler> handler_; 275 static constexpr size_t PARAM_POS_ZERO = 0; 276 static constexpr size_t PARAM_POS_ONE = 1; 277 static constexpr size_t PARAM_POS_TWO = 2; 278 static constexpr size_t PARAM_POS_THREE = 3; 279 static BlockQueue<MessageHandlerInfo> messageHandlerQueue_; 280 static BlockQueue<AttachInfo> attachQueue_; 281 }; 282 } // namespace MiscServices 283 } // namespace OHOS 284 #endif // INTERFACE_KITS_JS_GET_INPUT_METHOD_CONTROLLER_H