summaryrefslogtreecommitdiffstats
path: root/src/plugins/platforms/wasm/qwasminputcontext.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/platforms/wasm/qwasminputcontext.cpp')
-rw-r--r--src/plugins/platforms/wasm/qwasminputcontext.cpp309
1 files changed, 104 insertions, 205 deletions
diff --git a/src/plugins/platforms/wasm/qwasminputcontext.cpp b/src/plugins/platforms/wasm/qwasminputcontext.cpp
index 2df7066b8e2..191e2947629 100644
--- a/src/plugins/platforms/wasm/qwasminputcontext.cpp
+++ b/src/plugins/platforms/wasm/qwasminputcontext.cpp
@@ -25,105 +25,88 @@ void QWasmInputContext::inputCallback(emscripten::val event)
{
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "isComposing : " << event["isComposing"].as<bool>();
- QString inputStr = (event["data"] != emscripten::val::null()
- && event["data"] != emscripten::val::undefined()) ?
- QString::fromStdString(event["data"].as<std::string>()) : QString();
-
- QWasmInputContext *wasmInput =
- reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>());
-
emscripten::val inputType = event["inputType"];
- if (inputType != emscripten::val::null()
- && inputType != emscripten::val::undefined()) {
- const auto inputTypeString = inputType.as<std::string>();
- // There are many inputTypes for InputEvent
- // https://www.w3.org/TR/input-events-1/
- // Some of them should be implemented here later.
- qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType : " << inputTypeString;
- if (!inputTypeString.compare("deleteContentBackward")) {
- QWindowSystemInterface::handleKeyEvent(0,
- QEvent::KeyPress,
- Qt::Key_Backspace,
- Qt::NoModifier);
- QWindowSystemInterface::handleKeyEvent(0,
- QEvent::KeyRelease,
- Qt::Key_Backspace,
- Qt::NoModifier);
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("deleteContentForward")) {
- QWindowSystemInterface::handleKeyEvent(0,
- QEvent::KeyPress,
- Qt::Key_Delete,
- Qt::NoModifier);
- QWindowSystemInterface::handleKeyEvent(0,
- QEvent::KeyRelease,
- Qt::Key_Delete,
- Qt::NoModifier);
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("insertCompositionText")) {
- qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr;
- wasmInput->insertPreedit();
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("insertReplacementText")) {
- qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr;
- //auto ranges = event.call<emscripten::val>("getTargetRanges");
- //qCDebug(qLcQpaWasmInputContext) << ranges["length"].as<int>();
- // WA For Korean IME
- // insertReplacementText should have targetRanges but
- // Safari cannot have it and just it seems to be supposed
- // to replace previous input.
- wasmInput->insertText(inputStr, true);
-
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("deleteCompositionText")) {
- wasmInput->setPreeditString("", 0);
- wasmInput->insertPreedit();
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("insertFromComposition")) {
- wasmInput->setPreeditString(inputStr, 0);
- wasmInput->insertPreedit();
- event.call<void>("stopImmediatePropagation");
- return;
- } else if (!inputTypeString.compare("insertText")) {
- wasmInput->insertText(inputStr);
- event.call<void>("stopImmediatePropagation");
+ if (inputType.isNull() || inputType.isUndefined())
+ return;
+ const auto inputTypeString = inputType.as<std::string>();
+
+ emscripten::val inputData = event["data"];
+ QString inputStr = (!inputData.isNull() && !inputData.isUndefined())
+ ? QString::fromEcmaString(inputData) : QString();
+
+ // There are many inputTypes for InputEvent
+ // https://www.w3.org/TR/input-events-1/
+ // Some of them should be implemented here later.
+ qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType : " << inputTypeString;
+ if (!inputTypeString.compare("deleteContentBackward")) {
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_Backspace, Qt::NoModifier);
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_Backspace, Qt::NoModifier);
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("deleteContentForward")) {
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyPress, Qt::Key_Delete, Qt::NoModifier);
+ QWindowSystemInterface::handleKeyEvent(0, QEvent::KeyRelease, Qt::Key_Delete, Qt::NoModifier);
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("insertCompositionText")) {
+ qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr;
+ insertPreedit();
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("insertReplacementText")) {
+ qCDebug(qLcQpaWasmInputContext) << "inputString : " << inputStr;
+ //auto ranges = event.call<emscripten::val>("getTargetRanges");
+ //qCDebug(qLcQpaWasmInputContext) << ranges["length"].as<int>();
+ // WA For Korean IME
+ // insertReplacementText should have targetRanges but
+ // Safari cannot have it and just it seems to be supposed
+ // to replace previous input.
+ insertText(inputStr, true);
+
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("deleteCompositionText")) {
+ setPreeditString("", 0);
+ insertPreedit();
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("insertFromComposition")) {
+ setPreeditString(inputStr, 0);
+ insertPreedit();
+ event.call<void>("stopImmediatePropagation");
+ return;
+ } else if (!inputTypeString.compare("insertText")) {
+ insertText(inputStr);
+ event.call<void>("stopImmediatePropagation");
#if QT_CONFIG(clipboard)
- } else if (!inputTypeString.compare("insertFromPaste")) {
- wasmInput->insertText(QGuiApplication::clipboard()->text());
- event.call<void>("stopImmediatePropagation");
- // These can be supported here,
- // But now, keyCallback in QWasmWindow
- // will take them as exceptions.
- //} else if (!inputTypeString.compare("deleteByCut")) {
+ } else if (!inputTypeString.compare("insertFromPaste")) {
+ insertText(QGuiApplication::clipboard()->text());
+ event.call<void>("stopImmediatePropagation");
+ // These can be supported here,
+ // But now, keyCallback in QWasmWindow
+ // will take them as exceptions.
+ //} else if (!inputTypeString.compare("deleteByCut")) {
#endif
- } else {
- qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType \"" << inputType.as<std::string>() << "\" is not supported in Qt yet";
- }
+ } else {
+ qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO << "inputType \"" <<
+ inputType.as<std::string>() << "\" is not supported in Qt yet";
}
}
void QWasmInputContext::compositionEndCallback(emscripten::val event)
{
- const auto inputStr = QString::fromStdString(event["data"].as<std::string>());
+ const auto inputStr = QString::fromEcmaString(event["data"]);
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << inputStr;
- QWasmInputContext *wasmInput =
- reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>());
-
- if (wasmInput->preeditString().isEmpty())
+ if (preeditString().isEmpty())
return;
- if (inputStr != wasmInput->preeditString()) {
+ if (inputStr != preeditString()) {
qCWarning(qLcQpaWasmInputContext) << Q_FUNC_INFO
<< "Composition string" << inputStr
- << "is differ from" << wasmInput->preeditString();
+ << "is differ from" << preeditString();
}
- wasmInput->commitPreeditAndClear();
+ commitPreeditAndClear();
}
void QWasmInputContext::compositionStartCallback(emscripten::val event)
@@ -151,19 +134,15 @@ static void beforeInputCallback(emscripten::val event)
void QWasmInputContext::compositionUpdateCallback(emscripten::val event)
{
- const auto compositionStr = QString::fromStdString(event["data"].as<std::string>());
+ const auto compositionStr = QString::fromEcmaString(event["data"]);
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << compositionStr;
- QWasmInputContext *wasmInput =
- reinterpret_cast<QWasmInputContext *>(event["target"]["data-qinputcontext"].as<quintptr>());
-
// WA for IOS.
// Not sure now because I cannot test it anymore.
// int replaceSize = 0;
// emscripten::val win = emscripten::val::global("window");
// emscripten::val sel = win.call<emscripten::val>("getSelection");
-// if (sel != emscripten::val::null()
-// && sel != emscripten::val::undefined()
+// if (!sel.isNull() && !sel.isUndefined()
// && sel["rangeCount"].as<int>() > 0) {
// QInputMethodQueryEvent queryEvent(Qt::ImQueryAll);
// QCoreApplication::sendEvent(QGuiApplication::focusObject(), &queryEvent);
@@ -172,8 +151,8 @@ void QWasmInputContext::compositionUpdateCallback(emscripten::val event)
// qCDebug(qLcQpaWasmInputContext) << "Qt text before cursor: " << queryEvent.value(Qt::ImTextBeforeCursor).toString();
// qCDebug(qLcQpaWasmInputContext) << "Qt text after cursor: " << queryEvent.value(Qt::ImTextAfterCursor).toString();
//
-// const QString &selectedStr = QString::fromUtf8(sel.call<emscripten::val>("toString").as<std::string>());
-// const auto &preeditStr = wasmInput->preeditString();
+// const QString &selectedStr = QString::fromEcmaString(sel.call<emscripten::val>("toString"));
+// const auto &preeditStr = preeditString();
// qCDebug(qLcQpaWasmInputContext) << "Selection.type : " << sel["type"].as<std::string>();
// qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "Selected: " << selectedStr;
// qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "PreeditString: " << preeditStr;
@@ -189,90 +168,13 @@ void QWasmInputContext::compositionUpdateCallback(emscripten::val event)
// qCDebug(qLcQpaWasmInputContext) << "Range.endOffset : " << range["endOffset"].as<int>();
// }
//
-// wasmInput->setPreeditString(compositionStr, replaceSize);
- wasmInput->setPreeditString(compositionStr, 0);
-}
-
-#if QT_CONFIG(clipboard)
-static void copyCallback(emscripten::val event)
-{
- qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
-
- QClipboard *clipboard = QGuiApplication::clipboard();
- QString inputStr = clipboard->text();
- qCDebug(qLcQpaWasmInputContext) << "QClipboard : " << inputStr;
- event["clipboardData"].call<void>("setData",
- emscripten::val("text/plain"),
- inputStr.toStdString());
- event.call<void>("preventDefault");
- event.call<void>("stopImmediatePropagation");
-}
-
-static void cutCallback(emscripten::val event)
-{
- qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
-
- QClipboard *clipboard = QGuiApplication::clipboard();
- QString inputStr = clipboard->text();
- qCDebug(qLcQpaWasmInputContext) << "QClipboard : " << inputStr;
- event["clipboardData"].call<void>("setData",
- emscripten::val("text/plain"),
- inputStr.toStdString());
- event.call<void>("preventDefault");
- event.call<void>("stopImmediatePropagation");
+// setPreeditString(compositionStr, replaceSize);
+ setPreeditString(compositionStr, 0);
}
-static void pasteCallback(emscripten::val event)
-{
- qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
-
- emscripten::val clipboardData = event["clipboardData"].call<emscripten::val>("getData", emscripten::val("text/plain"));
- QString clipboardStr = QString::fromStdString(clipboardData.as<std::string>());
- qCDebug(qLcQpaWasmInputContext) << "wasm clipboard : " << clipboardStr;
- QClipboard *clipboard = QGuiApplication::clipboard();
- if (clipboard->text() != clipboardStr)
- clipboard->setText(clipboardStr);
-
- // propagate to input event (insertFromPaste)
-}
-#endif // QT_CONFIG(clipboard)
-
QWasmInputContext::QWasmInputContext()
{
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO;
- emscripten::val document = emscripten::val::global("document");
- // This 'input' can be an issue to handle multiple lines,
- // 'textarea' can be used instead.
- m_inputElement = document.call<emscripten::val>("createElement", std::string("input"));
- m_inputElement.set("type", "text");
- m_inputElement.set("contenteditable","true");
- m_inputElement.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
-
- m_inputElement["style"].set("position", "absolute");
- m_inputElement["style"].set("left", 0);
- m_inputElement["style"].set("top", 0);
- m_inputElement["style"].set("opacity", 0);
- m_inputElement["style"].set("display", "");
- m_inputElement["style"].set("z-index", -2);
- m_inputElement["style"].set("width", "1px");
- m_inputElement["style"].set("height", "1px");
-
- m_inputElement.set("data-qinputcontext",
- emscripten::val(quintptr(reinterpret_cast<void *>(this))));
- emscripten::val body = document["body"];
- body.call<void>("appendChild", m_inputElement);
-
- m_inputCallback = QWasmEventHandler(m_inputElement, "input", QWasmInputContext::inputCallback);
- m_compositionEndCallback = QWasmEventHandler(m_inputElement, "compositionend", QWasmInputContext::compositionEndCallback);
- m_compositionStartCallback = QWasmEventHandler(m_inputElement, "compositionstart", QWasmInputContext::compositionStartCallback);
- m_compositionUpdateCallback = QWasmEventHandler(m_inputElement, "compositionupdate", QWasmInputContext::compositionUpdateCallback);
-
-#if QT_CONFIG(clipboard)
- // Clipboard for InputContext
- m_clipboardCut = QWasmEventHandler(m_inputElement, "cut", cutCallback);
- m_clipboardCopy = QWasmEventHandler(m_inputElement, "copy", copyCallback);
- m_clipboardPaste = QWasmEventHandler(m_inputElement, "paste", pasteCallback);
-#endif
}
QWasmInputContext::~QWasmInputContext()
@@ -303,6 +205,9 @@ void QWasmInputContext::showInputPanel()
void QWasmInputContext::updateGeometry()
{
+ if (m_inputElement.isNull())
+ return;
+
const QWindow *focusWindow = QGuiApplication::focusWindow();
if (!m_focusObject || !focusWindow || !m_inputMethodAccepted) {
m_inputElement["style"].set("left", "0px");
@@ -312,23 +217,12 @@ void QWasmInputContext::updateGeometry()
Q_ASSERT(m_focusObject);
Q_ASSERT(m_inputMethodAccepted);
- // Set the geometry
- QPoint globalPos;
- const QRect cursorRectangle = QPlatformInputContext::cursorRectangle().toRect();
- if (cursorRectangle.isValid()) {
- qCDebug(qLcQpaWasmInputContext)
- << Q_FUNC_INFO << "cursorRectangle: " << cursorRectangle;
- globalPos = focusWindow->mapToGlobal(cursorRectangle.topLeft());
- if (globalPos.x() > 0)
- globalPos.setX(globalPos.x() - 1);
- if (globalPos.y() > 0)
- globalPos.setY(globalPos.y() - 1);
- }
-
- const auto styleLeft = std::to_string(globalPos.x()) + "px";
- const auto styleTop = std::to_string(globalPos.y()) + "px";
- m_inputElement["style"].set("left", styleLeft);
- m_inputElement["style"].set("top", styleTop);
+ const QRect inputItemRectangle = QPlatformInputContext::inputItemRectangle().toRect();
+ qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << "propagating inputItemRectangle:" << inputItemRectangle;
+ m_inputElement["style"].set("left", std::to_string(inputItemRectangle.x()) + "px");
+ m_inputElement["style"].set("top", std::to_string(inputItemRectangle.y()) + "px");
+ m_inputElement["style"].set("width", std::to_string(inputItemRectangle.width()) + "px");
+ m_inputElement["style"].set("height", std::to_string(inputItemRectangle.height()) + "px");
}
}
@@ -341,16 +235,21 @@ void QWasmInputContext::updateInputElement()
updateGeometry();
// If there is no focus object, or no visible input panel, remove focus
- const QWindow *focusWindow = QGuiApplication::focusWindow();
+ QWasmWindow *focusWindow = QWasmWindow::fromWindow(QGuiApplication::focusWindow());
if (!m_focusObject || !focusWindow || !m_inputMethodAccepted) {
- m_inputElement.set("value", "");
+ if (!m_inputElement.isNull()) {
+ m_inputElement.set("value", "");
+ m_inputElement.set("inputMode", std::string("none"));
+ }
- if (QWasmWindow *wasmwindow = QWasmWindow::fromWindow(focusWindow))
- wasmwindow->focus();
- else
- m_inputElement.call<void>("blur");
+ if (focusWindow) {
+ focusWindow->focus();
+ } else {
+ if (!m_inputElement.isNull())
+ m_inputElement.call<void>("blur");
+ }
- m_inputElement.set("inputMode", std::string("none"));
+ m_inputElement = emscripten::val::null();
return;
}
@@ -358,6 +257,8 @@ void QWasmInputContext::updateInputElement()
Q_ASSERT(m_focusObject);
Q_ASSERT(m_inputMethodAccepted);
+ m_inputElement = focusWindow->inputElement();
+
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << QRectF::fromDOMRect(m_inputElement.call<emscripten::val>("getBoundingClientRect"));
// Set the text input
@@ -375,7 +276,15 @@ void QWasmInputContext::updateInputElement()
m_inputElement.set("selectionStart", queryEvent.value(Qt::ImAnchorPosition).toUInt());
m_inputElement.set("selectionEnd", queryEvent.value(Qt::ImCursorPosition).toUInt());
+ QInputMethodQueryEvent query((Qt::InputMethodQueries(Qt::ImHints)));
+ QCoreApplication::sendEvent(m_focusObject, &query);
+ if (Qt::InputMethodHints(query.value(Qt::ImHints).toInt()).testFlag(Qt::ImhHiddenText))
+ m_inputElement.set("type", "password");
+ else
+ m_inputElement.set("type", "text");
+
m_inputElement.set("inputMode", std::string("text"));
+
m_inputElement.call<void>("focus");
}
@@ -383,16 +292,6 @@ void QWasmInputContext::setFocusObject(QObject *object)
{
qCDebug(qLcQpaWasmInputContext) << Q_FUNC_INFO << object << inputMethodAccepted();
- QInputMethodQueryEvent query(Qt::InputMethodQueries(Qt::ImEnabled | Qt::ImHints));
- QCoreApplication::sendEvent(object, &query);
- if (query.value(Qt::ImEnabled).toBool()
- && Qt::InputMethodHints(query.value(Qt::ImHints).toInt()).testFlag(Qt::ImhHiddenText)) {
- m_inputElement.set("type", "password");
- } else {
- if (m_inputElement["type"].as<std::string>() != std::string("text"))
- m_inputElement.set("type", "text");
- }
-
// Commit the previous composition before change m_focusObject
if (m_focusObject && !m_preeditString.isEmpty())
commitPreeditAndClear();