wasm: Make sure typing with window focus does not produce characters

contenteditable on the window caused characters to be inserted.
Instead create a div as a child element, and set  contenteditable
on that.

Fixes: QTBUG-136050
Change-Id: I4ccf3589ea19876f68bb9c7077c3a13ae5f989e6
Reviewed-by: Lorn Potter <lorn.potter@qt.io>
This commit is contained in:
Even Oscar Andersen 2025-04-24 06:37:52 +02:00
parent 6a3b653fe6
commit 1192a9d81a
4 changed files with 48 additions and 15 deletions

View File

@ -46,7 +46,7 @@ static void commonCopyEvent(val event)
event.call<void>("preventDefault");
}
static void qClipboardCutTo(val event)
void QWasmClipboard::cut(val event)
{
QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
if (wasmInput && wasmInput->usingTextInput())
@ -61,7 +61,7 @@ static void qClipboardCutTo(val event)
commonCopyEvent(event);
}
static void qClipboardCopyTo(val event)
void QWasmClipboard::copy(val event)
{
QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
if (wasmInput && wasmInput->usingTextInput())
@ -75,7 +75,7 @@ static void qClipboardCopyTo(val event)
commonCopyEvent(event);
}
static void qClipboardPasteTo(val event)
void QWasmClipboard::paste(val event)
{
QWasmInputContext *wasmInput = QWasmIntegration::get()->wasmInputContext();
if (wasmInput && wasmInput->usingTextInput())
@ -86,10 +86,26 @@ static void qClipboardPasteTo(val event)
QWasmIntegration::get()->getWasmClipboard()->sendClipboardData(event);
}
void QWasmClipboard::beforeInput(emscripten::val event)
{
event.call<void>("preventDefault");
event.call<void>("stopPropagation");
}
void QWasmClipboard::input(emscripten::val event)
{
event.call<void>("preventDefault");
event.call<void>("stopPropagation");
event["target"].set("innerHTML", std::string());
event["target"].set("value", std::string());
}
EMSCRIPTEN_BINDINGS(qtClipboardModule) {
function("qtClipboardCutTo", &qClipboardCutTo);
function("qtClipboardCopyTo", &qClipboardCopyTo);
function("qtClipboardPasteTo", &qClipboardPasteTo);
function("qtClipboardCutTo", &QWasmClipboard::cut);
function("qtClipboardCopyTo", &QWasmClipboard::copy);
function("qtClipboardPasteTo", &QWasmClipboard::paste);
function("qtClipboardBeforeInput", &QWasmClipboard::beforeInput);
function("qtClipboardInput", &QWasmClipboard::input);
}
QWasmClipboard::QWasmClipboard()
@ -167,7 +183,7 @@ void QWasmClipboard::initClipboardPermissions()
})());
}
void QWasmClipboard::installEventHandlers(const emscripten::val &target)
void QWasmClipboard::installEventHandlers(emscripten::val &target)
{
emscripten::val cContext = val::undefined();
emscripten::val isChromium = val::global("window")["chrome"];
@ -175,7 +191,17 @@ void QWasmClipboard::installEventHandlers(const emscripten::val &target)
cContext = val::global("document");
} else {
cContext = target;
// Set contentEditable so that the window gets clipboard events,
// then hide the resulting focus frame.
cContext.set("contentEditable", std::string("true"));
cContext["style"].set("outline", std::string("none"));
cContext.call<void>("addEventListener", val("beforeinput"),
val::module_property("qtClipboardBeforeInput"), true);
cContext.call<void>("addEventListener", val("input"),
val::module_property("qtClipboardInput"), true);
}
// Fallback path for browsers which do not support direct clipboard access
cContext.call<void>("addEventListener", val("cut"),
val::module_property("qtClipboardCutTo"), true);

View File

@ -36,10 +36,16 @@ public:
bool ownsMode(QClipboard::Mode mode) const override;
ProcessKeyboardResult processKeyboard(const KeyEvent &event);
static void installEventHandlers(const emscripten::val &target);
static void installEventHandlers(emscripten::val &target);
bool hasClipboardApi();
void sendClipboardData(emscripten::val event);
static void cut(emscripten::val event);
static void copy(emscripten::val event);
static void paste(emscripten::val event);
static void beforeInput(emscripten::val event);
static void input(emscripten::val event);
private:
void initClipboardPermissions();
void writeToClipboardApi();

View File

@ -56,6 +56,7 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_document(dom::document()),
m_decoratedWindow(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
m_window(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
m_windowInput(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
m_a11yContainer(m_document.call<emscripten::val>("createElement", emscripten::val("div"))),
m_canvas(m_document.call<emscripten::val>("createElement", emscripten::val("canvas")))
{
@ -70,18 +71,17 @@ QWasmWindow::QWasmWindow(QWindow *w, QWasmDeadKeySupport *deadKeySupport,
m_window.set("className", "qt-window");
m_decoratedWindow.call<void>("appendChild", m_window);
m_window.call<void>("appendChild", m_windowInput);
m_canvas["classList"].call<void>("add", emscripten::val("qt-window-canvas"));
// Set contentEditable so that the window gets clipboard events,
// then hide the resulting focus frame.
m_window.set("contentEditable", std::string("true"));
m_window["style"].set("outline", std::string("none"));
QWasmClipboard::installEventHandlers(m_window);
#if QT_CONFIG(clipboard)
QWasmClipboard::installEventHandlers(m_windowInput);
#endif
// Set inputMode to none to stop the mobile keyboard from opening
// when the user clicks on the window.
m_window.set("inputMode", std::string("none"));
m_windowInput.set("inputMode", std::string("none"));
// Hide the canvas from screen readers.
m_canvas.call<void>("setAttribute", std::string("aria-hidden"), std::string("true"));
@ -713,7 +713,7 @@ void QWasmWindow::requestActivateWindow()
void QWasmWindow::focus()
{
m_canvas.call<void>("focus");
m_windowInput.call<void>("focus");
}
bool QWasmWindow::setMouseGrabEnabled(bool grab)

View File

@ -140,6 +140,7 @@ private:
emscripten::val m_document;
emscripten::val m_decoratedWindow;
emscripten::val m_window;
emscripten::val m_windowInput;
emscripten::val m_a11yContainer;
emscripten::val m_canvas;
emscripten::val m_context2d = emscripten::val::undefined();