5#include <QtCore/private/qohoslogger_p.h>
6#include <QtCore/private/qstringconverter_p.h>
9#include <qarkui/qarkuiutils.h>
10#include <qohosplugincore.h>
11#include <qohosutils.h>
19#ifdef __cpp_lib_string_resize_and_overwrite
23 const auto maxBytes = utf16String.size() * 3;
24 utf8Str.resize_and_overwrite(maxBytes, [&] (
char *dst, size_t)
noexcept {
25 return QUtf8::convertFromUnicode(dst, QStringView{utf16String}) - dst;
30QT_WARNING_DISABLE_DEPRECATED
31 return std::wstring_convert<std::codecvt_utf8_utf16<
char16_t>,
char16_t>{}.to_bytes(utf16String);
38 return std::shared_ptr<::InputMethod_TextEditorProxy>(
39 QArkUi::callArkUiOrFailOnNullResult(
40 Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_Create)),
41 [](::InputMethod_TextEditorProxy *textEditorProxy) {
43 Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_Destroy),
49 bool showKeyboard, ::InputMethod_RequestKeyboardReason requestKeyboardReason)
51 return std::shared_ptr<::InputMethod_AttachOptions>(
52 QArkUi::callArkUiOrFailOnNullResult(
53 Q_OHOS_NAMED_FUNC(::OH_AttachOptions_CreateWithRequestKeyboardReason),
54 showKeyboard, requestKeyboardReason),
55 [](::InputMethod_AttachOptions *attachOptions) {
57 Q_OHOS_NAMED_FUNC(::OH_AttachOptions_Destroy),
63 std::shared_ptr<::InputMethod_TextEditorProxy> textEditorProxy,
64 std::shared_ptr<::InputMethod_AttachOptions> attachOptions)
66 ::InputMethod_InputMethodProxy *inputMethodProxyPtr =
nullptr;
67 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
68 Q_OHOS_NAMED_FUNC(::OH_InputMethodController_Attach),
69 textEditorProxy.get(), attachOptions.get(), &inputMethodProxyPtr);
70 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK) {
71 qOhosPrintfError(
"%s: OH_InputMethodController_Attach failed!", Q_FUNC_INFO);
75 return std::shared_ptr<::InputMethod_InputMethodProxy>(
76 inputMethodProxyPtr, [](::InputMethod_InputMethodProxy *proxy) {
77 QArkUi::callArkUiOrFailOnErrorResult(
78 Q_OHOS_NAMED_FUNC(::OH_InputMethodController_Detach), proxy);
83 double x,
double y,
double width,
double height)
85 return std::shared_ptr<::InputMethod_CursorInfo>(
86 QArkUi::callArkUiOrFailOnNullResult(
87 Q_OHOS_NAMED_FUNC(::OH_CursorInfo_Create),
89 [](::InputMethod_CursorInfo *cursorInfo) {
91 Q_OHOS_NAMED_FUNC(::OH_CursorInfo_Destroy), cursorInfo);
95template<
typename CallbackResult,
typename... CallbackArgs>
98 typename CallbackResult,
99 typename... CallbackArgs,
100 ::InputMethod_ErrorCode rawSetCallbackFunc(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc<CallbackResult, CallbackArgs...>)>
102 ::InputMethod_TextEditorProxy *textEditorProxy,
103 QOhosNamedFunc<::InputMethod_ErrorCode(*)(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc<CallbackResult, CallbackArgs...>), rawSetCallbackFunc> setCallbackFunc,
104 std::function<CallbackResult(CallbackArgs...)> callback)
106 static std::map<::InputMethod_TextEditorProxy *, std::shared_ptr<std::function<CallbackResult(CallbackArgs...)>>> callbacksMap;
108 bool callbackRegistered;
109 std::tie(std::ignore, callbackRegistered) = callbacksMap.emplace(
111 std::make_shared<std::function<CallbackResult(CallbackArgs...)>>(std::move(callback)));
113 if (!callbackRegistered)
114 qOhosReportFatalErrorAndAbort(Q_FUNC_INFO,
"encountered duplicate callback registration for %p", textEditorProxy);
116 QArkUi::callArkUiOrFailOnErrorResult(
117 setCallbackFunc, textEditorProxy,
118 [](::InputMethod_TextEditorProxy *textEditorProxy, CallbackArgs ...callbackArgs) {
119 auto callbackIter = callbacksMap.find(textEditorProxy);
120 if (callbackIter != callbacksMap.end()) {
121 auto sharedCallback = callbackIter->second;
122 return (*sharedCallback)(callbackArgs...);
124 return CallbackResult();
128 return QtOhos::makeDestroyNotifier(
129 [textEditorProxy]() {
130 callbacksMap.erase(textEditorProxy);
135 typename CallbackResult,
136 typename... CallbackArgs,
137 ::InputMethod_ErrorCode rawSetCallbackFunc(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc<CallbackResult, CallbackArgs...>),
140 ::InputMethod_TextEditorProxy *textEditorProxy,
141 QOhosNamedFunc<::InputMethod_ErrorCode(*)(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc<CallbackResult, CallbackArgs...>), rawSetCallbackFunc> setCallbackFunc,
144 static_assert(
std::is_assignable<
std::function<CallbackResult(CallbackArgs...)>, Callback>::value,
"");
145 return registerTextEditorProxyCallbackImpl<CallbackResult>(
146 textEditorProxy, setCallbackFunc,
std::function<CallbackResult(CallbackArgs...)>(
std::move(callback)));
149template<
typename... CallbackArgs>
151 std::weak_ptr<QOhosInputMethodProxy::ClientCallbacks> weakClientCallbacks,
152 void (QOhosInputMethodProxy::ClientCallbacks::*callbackMemPtr)(CallbackArgs...),
153 CallbackArgs ...args)
155 QtOhos::invokeInQtThread(
156 [weakClientCallbacks, callbackMemPtr, args...]() {
157 auto clientCallbacks = weakClientCallbacks.lock();
159 (clientCallbacks.get()->*callbackMemPtr)(args...);
165std::shared_ptr<
void> QOhosInputMethodProxy::registerCallbacks(
166 std::shared_ptr<::InputMethod_TextEditorProxy> textEditorProxy,
167 std::shared_ptr<JsScopeData::JsTextEditorProxyData> textEditorProxyData,
168 std::weak_ptr<QOhosInputMethodProxy::ClientCallbacks> weakClientCallbacks)
170 std::vector<std::shared_ptr<
void>> registrationHandles;
172 registrationHandles.push_back(
173 registerTextEditorProxyCallback(
174 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetGetTextConfigFunc),
175 [](::InputMethod_TextConfig *config) {
176 QArkUi::callArkUiOrFailOnErrorResult(
177 Q_OHOS_NAMED_FUNC(::OH_TextConfig_SetPreviewTextSupport),
181 registrationHandles.push_back(
182 registerTextEditorProxyCallback(
183 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetInsertTextFunc),
184 [weakClientCallbacks](
const char16_t *text, size_t length) {
185 std::u16string utf16Text(text, length);
187 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onInsertText,
191 registrationHandles.push_back(
192 registerTextEditorProxyCallback(
193 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetDeleteForwardFunc),
194 [weakClientCallbacks](
std::int32_t length) {
196 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onDeleteForward,
200 registrationHandles.push_back(
201 registerTextEditorProxyCallback(
202 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetDeleteBackwardFunc),
203 [weakClientCallbacks](
std::int32_t length) {
205 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onDeleteBackward,
209 registrationHandles.push_back(
210 registerTextEditorProxyCallback(
211 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetSendKeyboardStatusFunc),
212 [weakClientCallbacks, weakTextEditorProxyData = QtOhos::makeWeakPtr(textEditorProxyData)](::InputMethod_KeyboardStatus keyboardStatus) {
213 auto sharedTextEditorProxyData = weakTextEditorProxyData.lock();
214 if (sharedTextEditorProxyData)
215 sharedTextEditorProxyData->textInputShown = keyboardStatus == ::IME_KEYBOARD_STATUS_SHOW;
218 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onSendKeyboardStatus,
222 registrationHandles.push_back(
223 registerTextEditorProxyCallback(
224 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetSendEnterKeyFunc),
225 [weakClientCallbacks](::InputMethod_EnterKeyType enterKeyType) {
227 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onSendEnterKey,
231 registrationHandles.push_back(
232 registerTextEditorProxyCallback(
233 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetMoveCursorFunc),
234 [weakClientCallbacks](::InputMethod_Direction direction) {
236 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onMoveCursor,
240 registrationHandles.push_back(
241 registerTextEditorProxyCallback(
242 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetHandleSetSelectionFunc),
246 registrationHandles.push_back(
247 registerTextEditorProxyCallback(
248 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetHandleExtendActionFunc),
252 registrationHandles.push_back(
253 registerTextEditorProxyCallback(
254 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetGetLeftTextOfCursorFunc),
258 registrationHandles.push_back(
259 registerTextEditorProxyCallback(
260 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetGetRightTextOfCursorFunc),
264 QArkUi::callArkUiOrFailOnErrorResult(
265 Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetGetTextIndexAtCursorFunc),
266 textEditorProxy.get(),
267 [](::InputMethod_TextEditorProxy *) {
271 QArkUi::callArkUiOrFailOnErrorResult(
272 Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetReceivePrivateCommandFunc),
273 textEditorProxy.get(),
274 [](::InputMethod_TextEditorProxy *, ::InputMethod_PrivateCommand **,
unsigned long) {
278 registrationHandles.push_back(
279 registerTextEditorProxyCallback(
280 textEditorProxy.get(),
281 Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetSetPreviewTextFunc),
282 [weakClientCallbacks](
const char16_t *text,
std::size_t length,
std::int32_t,
std::int32_t) {
283 std::u16string utf16Text(text, length);
285 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onInsertPreviewText,
290 registrationHandles.push_back(
291 registerTextEditorProxyCallback(
292 textEditorProxy.get(), Q_OHOS_NAMED_FUNC(::OH_TextEditorProxy_SetFinishTextPreviewFunc),
293 [weakClientCallbacks]() {
295 weakClientCallbacks, &QOhosInputMethodProxy::ClientCallbacks::onFinishPreviewText);
298 return QtOhos::moveToSharedPtr(std::move(registrationHandles));
301QOhosInputMethodProxy::QOhosInputMethodProxy(
302 std::shared_ptr<ClientCallbacks> clientCallbacks, ::InputMethod_RequestKeyboardReason requestKeyboardReason)
303 : m_clientCallbacks(clientCallbacks)
305 auto weakClientCallbacks = QtOhos::makeWeakPtr(clientCallbacks);
306 m_jsScopeData = QtOhos::evalInJsThread(
307 [&](
auto &) -> std::shared_ptr<JsScopeData> {
308 auto textEditorProxyData = std::make_shared<JsScopeData::JsTextEditorProxyData>();
309 auto textEditorProxy = makeTextEditorProxy();
310 auto callbacksRegistrationHandle = registerCallbacks(textEditorProxy, textEditorProxyData, weakClientCallbacks);
312 auto showKeyboard =
true;
313 auto attachOptions = makeAttachOptions(showKeyboard, requestKeyboardReason);
315 auto inputMethodProxy = tryMakeInputMethodProxy(textEditorProxy, attachOptions);
316 if (!inputMethodProxy) {
317 qOhosPrintfError(
"%s: inputMethodProxy is nullptr!", Q_FUNC_INFO);
321 return QtOhos::makeProxyWithJsThreadDeleter(
322 QtOhos::moveToSharedPtr(
324 .textEditorProxy = textEditorProxy,
325 .textEditorProxyData = textEditorProxyData,
326 .inputMethodProxy = inputMethodProxy,
327 .callbacksRegistrationHandle = callbacksRegistrationHandle,
333bool QOhosInputMethodProxy::hasAttachedSuccessfully()
335 return m_jsScopeData !=
nullptr;
338void QOhosInputMethodProxy::showTextInput(::InputMethod_RequestKeyboardReason requestKeyboardReason)
340 if (!hasAttachedSuccessfully()) {
341 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
347 if (m_jsScopeData->textEditorProxyData->textInputShown) {
348 qOhosPrintfDebug(
"%s: text input already shown, skip showing it again", Q_FUNC_INFO);
352 auto showKeyboard =
true;
353 auto attachOptions = makeAttachOptions(showKeyboard, requestKeyboardReason);
355 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
356 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_ShowTextInput),
357 m_jsScopeData->inputMethodProxy.get(),
358 attachOptions.get());
359 m_jsScopeData->textEditorProxyData->textInputShown = errcode == ::InputMethod_ErrorCode::IME_ERR_OK;
360 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
361 qOhosPrintfError(
"%s: OH_InputMethodProxy_ShowTextInput failed!", Q_FUNC_INFO);
366void QOhosInputMethodProxy::notifyConfigurationChange(
367 ::InputMethod_EnterKeyType enterKeyType, ::InputMethod_TextInputType textInputType)
369 if (!hasAttachedSuccessfully()) {
370 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
376 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
377 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_NotifyConfigurationChange),
378 m_jsScopeData->inputMethodProxy.get(),
379 enterKeyType, textInputType);
380 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
381 qOhosPrintfError(
"%s: OH_InputMethodProxy_NotifyConfigurationChange failed!", Q_FUNC_INFO);
386void QOhosInputMethodProxy::notifyCursorUpdate(
const QRectF &cursorRect)
388 if (!hasAttachedSuccessfully()) {
389 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
393 double x = cursorRect.x();
394 double y = cursorRect.y();
395 double width = cursorRect.width();
396 double height = cursorRect.height();
400 auto ohCursorInfo = makeCursorInfo(x, y, width, height);
402 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
403 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_NotifyCursorUpdate),
404 m_jsScopeData->inputMethodProxy.get(), ohCursorInfo.get());
405 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
406 qOhosPrintfError(
"%s: OH_InputMethodProxy_NotifyCursorUpdate failed!", Q_FUNC_INFO);
411QOhosInputMethodProxy::ClientCallbacks::ClientCallbacks() =
default;
413QOhosInputMethodProxy::ClientCallbacks::~ClientCallbacks() =
default;
Combined button and popup list for selecting options.
std::shared_ptr< void > registerTextEditorProxyCallback(::InputMethod_TextEditorProxy *textEditorProxy, QOhosNamedFunc<::InputMethod_ErrorCode(*)(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc< CallbackResult, CallbackArgs... >), rawSetCallbackFunc > setCallbackFunc, Callback callback)
void callInQtThread(std::weak_ptr< QOhosInputMethodProxy::ClientCallbacks > weakClientCallbacks, void(QOhosInputMethodProxy::ClientCallbacks::*callbackMemPtr)(CallbackArgs...), CallbackArgs ...args)
std::shared_ptr<::InputMethod_AttachOptions > makeAttachOptions(bool showKeyboard, ::InputMethod_RequestKeyboardReason requestKeyboardReason)
std::shared_ptr<::InputMethod_CursorInfo > makeCursorInfo(double x, double y, double width, double height)
std::shared_ptr< void > registerTextEditorProxyCallbackImpl(::InputMethod_TextEditorProxy *textEditorProxy, QOhosNamedFunc<::InputMethod_ErrorCode(*)(::InputMethod_TextEditorProxy *, TextEditorProxyCallbackFunc< CallbackResult, CallbackArgs... >), rawSetCallbackFunc > setCallbackFunc, std::function< CallbackResult(CallbackArgs...)> callback)
CallbackResult(::InputMethod_TextEditorProxy *, CallbackArgs...) TextEditorProxyCallbackFunc
std::string convertUtf16ToUtf8(const std::u16string &utf16String)
std::shared_ptr<::InputMethod_TextEditorProxy > makeTextEditorProxy()
std::shared_ptr<::InputMethod_InputMethodProxy > tryMakeInputMethodProxy(std::shared_ptr<::InputMethod_TextEditorProxy > textEditorProxy, std::shared_ptr<::InputMethod_AttachOptions > attachOptions)
void runInJsThreadAndWait(const std::function< void(JsState &)> &task, std::string callerContextName={})