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),
296 return QtOhos::moveToSharedPtr(std::move(registrationHandles));
299QOhosInputMethodProxy::QOhosInputMethodProxy(
300 std::shared_ptr<ClientCallbacks> clientCallbacks, ::InputMethod_RequestKeyboardReason requestKeyboardReason)
301 : m_clientCallbacks(clientCallbacks)
303 auto weakClientCallbacks = QtOhos::makeWeakPtr(clientCallbacks);
304 m_jsScopeData = QtOhos::evalInJsThread(
305 [&](
auto &) -> std::shared_ptr<JsScopeData> {
306 auto textEditorProxyData = std::make_shared<JsScopeData::JsTextEditorProxyData>();
307 auto textEditorProxy = makeTextEditorProxy();
308 auto callbacksRegistrationHandle = registerCallbacks(textEditorProxy, textEditorProxyData, weakClientCallbacks);
310 auto showKeyboard =
true;
311 auto attachOptions = makeAttachOptions(showKeyboard, requestKeyboardReason);
313 auto inputMethodProxy = tryMakeInputMethodProxy(textEditorProxy, attachOptions);
314 if (!inputMethodProxy) {
315 qOhosPrintfError(
"%s: inputMethodProxy is nullptr!", Q_FUNC_INFO);
319 return QtOhos::makeProxyWithJsThreadDeleter(
320 QtOhos::moveToSharedPtr(
322 .textEditorProxy = textEditorProxy,
323 .textEditorProxyData = textEditorProxyData,
324 .inputMethodProxy = inputMethodProxy,
325 .callbacksRegistrationHandle = callbacksRegistrationHandle,
330bool QOhosInputMethodProxy::hasAttachedSuccessfully()
332 return m_jsScopeData !=
nullptr;
335void QOhosInputMethodProxy::showTextInput(::InputMethod_RequestKeyboardReason requestKeyboardReason)
337 if (!hasAttachedSuccessfully()) {
338 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
344 if (m_jsScopeData->textEditorProxyData->textInputShown) {
345 qOhosPrintfDebug(
"%s: text input already shown, skip showing it again", Q_FUNC_INFO);
349 auto showKeyboard =
true;
350 auto attachOptions = makeAttachOptions(showKeyboard, requestKeyboardReason);
352 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
353 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_ShowTextInput),
354 m_jsScopeData->inputMethodProxy.get(),
355 attachOptions.get());
356 m_jsScopeData->textEditorProxyData->textInputShown = errcode == ::InputMethod_ErrorCode::IME_ERR_OK;
357 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
358 qOhosPrintfError(
"%s: OH_InputMethodProxy_ShowTextInput failed!", Q_FUNC_INFO);
362void QOhosInputMethodProxy::notifyConfigurationChange(
363 ::InputMethod_EnterKeyType enterKeyType, ::InputMethod_TextInputType textInputType)
365 if (!hasAttachedSuccessfully()) {
366 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
372 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
373 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_NotifyConfigurationChange),
374 m_jsScopeData->inputMethodProxy.get(),
375 enterKeyType, textInputType);
376 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
377 qOhosPrintfError(
"%s: OH_InputMethodProxy_NotifyConfigurationChange failed!", Q_FUNC_INFO);
381void QOhosInputMethodProxy::notifyCursorUpdate(
const QRectF &cursorRect)
383 if (!hasAttachedSuccessfully()) {
384 qOhosPrintfError(
"%s: operation aborted, IMC not attached.", Q_FUNC_INFO);
388 double x = cursorRect.x();
389 double y = cursorRect.y();
390 double width = cursorRect.width();
391 double height = cursorRect.height();
395 auto ohCursorInfo = makeCursorInfo(x, y, width, height);
397 ::InputMethod_ErrorCode errcode =
QArkUi::callArkUi(
398 Q_OHOS_NAMED_FUNC(::OH_InputMethodProxy_NotifyCursorUpdate),
399 m_jsScopeData->inputMethodProxy.get(), ohCursorInfo.get());
400 if (errcode != ::InputMethod_ErrorCode::IME_ERR_OK)
401 qOhosPrintfError(
"%s: OH_InputMethodProxy_NotifyCursorUpdate failed!", Q_FUNC_INFO);
405QOhosInputMethodProxy::ClientCallbacks::ClientCallbacks() =
default;
407QOhosInputMethodProxy::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)